Open In App

Real Estate Listings Platform using NextJS

In this article, we will explore the process of building a real estate listing platform using Next.js. real estate listings platform is a web application that aims to provide users with a comprehensive platform to browse and search for properties. The platform will cater to both buyers and sellers, offering a seamless experience for property listing, and searching.

Output Preview: Let us have a look at how the final output will look like.

gfge

Prerequisites:

Approach to Create Real Estate Listings Platform:

Steps to Create Real Estate Listing Platform:

Step 1: Create a application of NextJS using the following command.

npx create-next-app real-estate

Step 2: Navigate to project directory

cd real-estate

Step 3: Install the necessary package in your project using the following command.

npm install bootstrap
npm install react-icons --save

Step 4: Create the folder structure as shown below and create the files in respective folders.

Project Structure:

Screenshot-(57)

The updated dependencies in package.json file will look like:

"dependencies": {
"autoprefixer": "^10.4.18",
"bootstrap": "^5.3.3",
"next": "14.1.3",
"postcss": "^8.4.36",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.0.1"
}

Example: Implementation of the above approach using NextJS.

// page.js
import React from 'react'
import HomeListing
    from './components/Listings'

const page = () => {
    return (
        <div>
            <HomeListing />
        </div>
    )
}

export default page
// Navbar.js

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Link from 'next/link';
function Navbar() {
    return (
        <nav className="navbar navbar-expand-lg navbar-light bg-light shadow top-0">
            <div className="container">
                <a className="navbar-brand text-success" href="#">
                    GFG Estate
                </a>
                <button className="navbar-toggler"
                    type="button" data-toggle="collapse"
                    data-target="#navbarNav"
                    aria-controls="navbarNav"
                    aria-expanded="false"
                    aria-label="Toggle navigation">
                    <span className="navbar-toggler-icon"></span>
                </button>
                <div className="collapse navbar-collapse" id="navbarNav">
                    <ul className="navbar-nav">
                        <li className="nav-item">
                            <Link className="nav-link" href="/">Home</Link>
                        </li>
                        <li className="nav-item">
                            <Link className="nav-link"
                                href="AddListing">
                                Add New Listing
                            </Link>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    );
}

export default Navbar;
// Listings.js
'use client';
import React, { useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Navbar from './Navbar';
import { FaLocationDot } from "react-icons/fa6";

const HomeListing = () => {
    // Retrieve listings from local storage
    const storedListings = localStorage.getItem('listings');
    const allListings = storedListings ? JSON.parse(storedListings) : [];
    const [listings, setListings] = useState(allListings);
    const [filter, setFilter] = useState('all');
    const [searchTerm, setSearchTerm] = useState('');

    const handleFilterChange = (e) => {
        const value = e.target.value;
        setFilter(value);
        if (value === 'all') {
            setListings(allListings);
        } else if (value === 'rent') {
            const rentListings =
                allListings.filter(
                    (listing) =>
                        listing.listingType === 'rent');
            setListings(rentListings);
        } else if (value === 'sale') {
            const saleListings =
                allListings.filter(
                    (listing) =>
                        listing.listingType === 'sale');
            setListings(saleListings);
        }
    };

    const handleSearchChange = (e) => {
        setSearchTerm(e.target.value);
        const filteredListings =
            allListings.filter((listing) =>
                listing.title.toLowerCase()
                    .includes(e.target.value.toLowerCase())
            );
        setListings(filteredListings);
    };

    return (
        <>
            <Navbar />
            <div className="container mt-5">
                <div className="row">
                    <div className="col-md-3">
                        <div className="mb-3">
                            <p>Type:</p>

                            <label className="form-check-label me-3"
                                style={{ fontSize: '1.2rem' }}>
                                <input
                                    type="checkbox"
                                    name="filter"
                                    value="all"
                                    checked={filter === 'all'}
                                    onChange={handleFilterChange}
                                    style={{ transform: 'scale(1.5)' }} />
                                {' '}All
                            </label>
                            <label className="form-check-label me-3"
                                style={{ fontSize: '1.2rem' }}>
                                <input
                                    type="checkbox"
                                    name="filter"
                                    value="rent"
                                    checked={filter === 'rent'}
                                    onChange={handleFilterChange}
                                    style={{ transform: 'scale(1.5)' }} />
                                {' '}Rent
                            </label>
                            <label className="form-check-label"
                                style={{ fontSize: '1.2rem' }}>
                                <input
                                    type="checkbox"
                                    name="filter"
                                    value="sale"
                                    checked={filter === 'sale'}
                                    onChange={handleFilterChange}
                                    style={{ transform: 'scale(1.5)' }} />
                                {' '}Sale
                            </label>

                        </div>
                        <div className="mb-3">
                            <label htmlFor="search"
                                className="form-label">Search</label>
                            <input
                                type="text"
                                className="form-control"
                                id="search"
                                value={searchTerm}
                                placeholder='seacrh...'
                                onChange={handleSearchChange}
                            />
                        </div>
                    </div>
                    <div className="col-md-9">
                        <div className="row">
                            {listings.map((listing) => (
                                <div key={listing.id}
                                    className="col-lg-4 col-md-6 mb-4">
                                    <div className="card">
                                        <div className="card-overlay">
                                            <img src={listing.imageData}
                                                className="card-img-top im"
                                                alt={listing.title}
                                                style={{ height: '200px' }} />
                                        </div>
                                        <div className="card-body">
                                            <h3 className="card-title">
                                                {listing.title}
                                            </h3>
                                            <p className="card-text">
                                                <FaLocationDot 
                                                    className='text-success' />
                                                {listing.location}
                                            </p>
                                            <div className="d-flex 
                                                justify-content-between">
                                                <p className="card-text">
                                                    {
                                                        listing.listingType ===
                                                        'sale' ? 'For Sale' : 'For Rent'
                                                    }
                                                </p>
                                                {listing.listingType === 'sale' ? (
                                                    <p className="card-text">
                                                        {listing.price}
                                                    </p>
                                                ) : (
                                                    <p className="card-text">
                                                        {listing.rent}/month
                                                    </p>
                                                )}
                                            </div>
                                            <button className='btn btn-outline-success w-100'>
                                                Explore
                                            </button>
                                        </div>
                                    </div>
                                </div>
                            ))}
                        </div>
                    </div>
                </div>
            </div>
            <style jsx>{`
        .card:hover {
          border-radius: 8px;
          transition: box-shadow 0.3s;
          width: 101%;
          box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
        }
      `}</style>
        </>
    );
};

export default HomeListing;
// AddListing.js

import React,
{
    useState
} from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import Navbar
    from '@/app/components/Navbar';

const AddListing = () => {
    const [title, setTitle] = useState('');
    const [description, setDescription] = useState('');
    const [price, setPrice] = useState('');
    const [rent, setRent] = useState('');
    const [location, setLocation] = useState('');
    const [image, setImage] = useState('');
    const [imageData, setImageData] = useState('');
    const [listingType, setListingType] = useState('sale');
    // Default to sale

    const handleSubmit = (e) => {
        e.preventDefault();
        console.log(
            {
                title, description,
                price, rent,
                location, image,
                imageData, listingType
            });

        // Save the form data and image data to local storage
        const listingData =
        {
            title, description,
            price, rent,
            location,
            image, imageData,
            listingType
        };
        const listings =
            JSON.parse(
                localStorage.getItem('listings')
            ) || [];
        listings.push(listingData);
        localStorage.setItem('listings', JSON.stringify(listings));

        // Reset form fields after submission
        setTitle('');
        setDescription('');
        setPrice('');
        setRent('');
        setLocation('');
        setImage('');
        setImageData('');
        setListingType('sale');
    };

    const handleImageChange = (e) => {
        const file = e.target.files[0];
        const reader = new FileReader();
        reader.onloadend = () => {
            setImageData(reader.result);
        };
        if (file) {
            reader.readAsDataURL(file);
            setImage(file.name);
        }
    };

    return (
        <>
            <Navbar />
            <div className="container" style={{ width: "70%" }}>
                <h2 className="mt-3 mb-4">Add New Listing</h2>
                <form onSubmit={handleSubmit}>
                    <div className="mb-3">
                        <label htmlFor="title"
                            className="form-label">
                            Title
                        </label>
                        <input
                            type="text"
                            className="form-control"
                            id="title"
                            value={title}
                            onChange={
                                (e) =>
                                    setTitle(e.target.value)
                            }
                            required />
                    </div>
                    <div className="mb-3">
                        <label htmlFor="description"
                            className="form-label">
                            Description
                        </label>
                        <textarea
                            className="form-control"
                            id="description"
                            value={description}
                            onChange={
                                (e) =>
                                    setDescription(e.target.value)
                            }
                            required
                        ></textarea>
                    </div>
                    <div className="mb-3">
                        <label htmlFor="location"
                            className="form-label">
                            Location
                        </label>
                        <input
                            type="text"
                            className="form-control"
                            id="location"
                            value={location}
                            onChange={
                                (e) =>
                                    setLocation(e.target.value)
                            }
                            required
                        />
                    </div>
                    <div className="mb-3">
                        <label htmlFor="listingType"
                            className="form-label">
                            Listing Type
                        </label>
                        <select
                            className="form-control"
                            id="listingType"
                            value={listingType}
                            onChange={(e) => setListingType(e.target.value)}
                            required>
                            <option value="sale">For Sale</option>
                            <option value="rent">For Rent</option>
                        </select>
                    </div>
                    {listingType === 'sale' && (
                        <div className="mb-3">
                            <label htmlFor="price"
                                className="form-label">
                                Price
                            </label>
                            <input
                                type="text"
                                className="form-control"
                                id="price"
                                value={price}
                                onChange={(e) => setPrice(e.target.value)}
                                required />
                        </div>
                    )}
                    {listingType === 'rent' && (
                        <div className="mb-3">
                            <label htmlFor="rent"
                                className="form-label">
                                Rent per Month
                            </label>
                            <input
                                type="text"
                                className="form-control"
                                id="rent"
                                value={rent}
                                onChange={
                                    (e) =>
                                        setRent(e.target.value)
                                }
                                required
                            />
                        </div>
                    )}
                    <div className="mb-3">
                        <label htmlFor="image"
                            className="form-label">Image</label>
                        <input
                            type="file"
                            className="form-control"
                            id="image"
                            accept="image/*"
                            onChange={handleImageChange}
                            required
                        />
                    </div>
                    {imageData && (
                        <img src={imageData}
                            alt="Selected"
                            className="img-fluid mb-3"
                            style={{ maxWidth: '200px' }} />
                    )}
                    <button type="submit"
                        className="btn btn-primary">
                        Add Listing
                    </button>
                </form>
            </div>
        </>
    );
};

export default AddListing;

Start your application using the following command:

npm run dev

Output: Naviage to the URL http://localhost:3000:

gfgef

Article Tags :