ReactJS-The Beginner Master Class
  • React In the Beginning
    • Lesson 1 - Demo: Build a Simple React App - Fast
    • Lesson 2 - HTML Review
    • Lesson 3 - CSS Review
    • Lesson 4 - Modern JavaScript (JSX) Patterns
    • Lesson 5 - Set up Dev Environment
    • Hands-on Practice
  • React Fundamentals
    • Lesson 1 - Understanding Old vs New Way of Building Web Apps - SPAs
    • Lesson 2 - Motivation for Using React as the Solution to Vanilla JS
    • Lesson 3 - What is ReactJS - How it Works
    • React Code Along from Scratch
    • Lesson 4 - Create and Run a React Project with Vite - Full Overview
    • Lesson 5 - Create Hook by State Management in React
    • Lesson 6 - React Project File and Folder Walkthrough
    • Lesson 7 - JSX and How React Treats the DOM & JSX Compilation(by Babeljs) - Overview
    • Lesson 8 - Understanding the Main Files - App.jsx and main.jsx
    • Lesson 9 - Props and One-Way Data Flow - Overview
    • Lesson 10 - Google Bookshelf App - Ver 1.0
    • Hands-on Practice I
    • Hands-on Practice II
  • React State and Styling
    • Lesson 1 - Pulling Book Data from a Different Data File
    • Lesson 2 - Overview of How State Works in React
    • Lesson 3 - RandomQuote App
    • Lesson 4 - Lifting State Up - React Pattern Overview
    • Hands-On - Simple Counter
  • Forms and Interactivity - Grocery List App
    • Lesson 1 - Setup a Simple Form and Input
    • Lesson 2 - Build Form Profile App Using Multi-input Form Data
    • Hands-on : Build a Grocery List App
  • Connecting to the Backend - Consuming APIs - UseEffect Hook
    • Lesson 1 - Connecting to the Back End - Understanding Side Effects, Hooks and useEffect - Overview
    • Lesson 2 - Fetching Data from the Backend the Right Way with useEffect Hook
    • Lesson 3 - Setting Up Loading State
    • Hands-on :Use Dependency Array and Adding Values that Control Side Effects
  • Solo Project 1
  • RESTful APIs :Build a BookSearch App -Ver 2.0
    • Lesson 1: Build and test RESTful APIs with Postman
    • Lesson 2 - BookShelf App Structure
    • Lesson 3 - Create NavBar.jsx Component
    • Lesson 4 - Create Footer Component
    • Lesson 5 - Create BookList.jsx Component
    • Lesson 6 - Create BookCard.jsx Component
    • Lesson 7 - Creating Custom Hooks - useBooks and api-client
    • Lesson 8 - Controlling Network Activities in React with AbortController
    • Lesson 9 - Show Book Details in a Modal - Working
    • Lesson 10 - Bookshelf App Summary
  • Multi-Page Applications (MPAs)
    • Build a Multi-Page React Application
    • Multi-Page React Application
    • Hands-on Practice
  • Backend Frameworks-NEXT.JS
    • Migrating from React to Next.js
    • Lesson 1: Key Concepts of NodeJS and Express for Backend Web Development
    • Lesson 2: How to set up a new Next.js project
    • Lesson 3: How to create Layouts and Pages
    • Hands-on Practice 1
    • Hands on Practice 2
      • New Project & Folder Structure
      • File-Based Routing
      • Server vs Client Components & Router Hooks
      • Start On The Navbar
      • Navbar Links, Dropdowns & React Icons
      • Active Links & Conditional Rendering
      • Homepage Components
      • Properties Page
      • Property Card Dynamic Data
      • Home Property Listings
      • Custom Not Found & Loading Pages
  • Git and GitHubs
    • Git Installation
    • Git Commands
    • GitHub Repository
    • Hands-on Practice
  • Database in Application
    • React Supabase CRUD
    • Hands-on: Note Taking App
  • NoSQL Database
    • Installing MongoDB Community Edition
    • System Env Path Setting
    • How to use MongoDB Shell
    • How to Connect and Use Mongosh in VS Code via MongoDB Extension
    • MongoDB Guide
  • Solo Project 2
  • Deployment and Web Hosting
    • Lesson 1. React+Vite+TS+Shadcn Project
    • Lesson 2. Deploying a React Vite App to Vercel from Vercel CLI
    • Lesson 3 Connecting to GitHub Repo and Automate Deployment
  • Solo Project 3
  • Final Term Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 1 Team Project
    • Level 2 Team Project
    • Level 2 Team Project
    • Level 3 Team Project
    • Level 3 Team Project
Powered by GitBook
On this page
  • Creating Properties Page Components
  • Preparations
  • 1. Set Up the Properties Page
  • 2. Build the Page Structure
  • 3. Render the Property Listings
  • 4. Create the Property Card Component
  • 5. Integrate the Property Card Component
  • 6. Leverage Next.js Rendering Strategies
  • 7. Test and Refine
  • Recap
  1. Backend Frameworks-NEXT.JS
  2. Hands on Practice 2

Properties Page

PreviousHomepage ComponentsNextProperty Card Dynamic Data

Last updated 2 months ago

Creating Properties Page Components

Preparations

Add properties.json file in your project root directory:

properties.json
// 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

1. Set Up the Properties Page

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.

b. Import the JSON Data

  • 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
// 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">
            &copy; 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

2. Build the Page Structure

a. Create a Container for Listings

  • 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

b. Implement Conditional Rendering for Empty Data

  • 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

3. Render the Property Listings

a. Loop Through the Properties Data

  • 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.


4. Create the Property Card Component

a. Create a New Component File

  • In the components/ folder, create a new file named PropertyCard.jsx:

    components/PropertyCard.jsx

b. Build the Component Structure

  • 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.


5. Integrate the Property Card Component

a. Import the PropertyCard Component

  • In your app/properties/page.jsx file, import the component at the top:

    import PropertyCard from '@/components/PropertyCard';

b. Use the Component in the Map Function

  • 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>

6. Leverage Next.js Rendering Strategies

a. Server Rendering for Static Data

  • 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.

b. Future Enhancements

  • 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.


7. Test and Refine

a. Run the Development Server

  • 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.

b. Adjust Styling and Layout

  • Refine the Tailwind CSS classes and layout to match your desired design.

  • Verify responsiveness on different screen sizes.


Recap

  • 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.

9KB
properties.json
properties.json
5MB
images.zip
archive