Open In App

Build a Photo Sharing App Using Next.js

Last Updated : 05 Aug, 2024
Summarize
Comments
Improve
Suggest changes
Share
Like Article
Like
Report

We will build a photo-sharing app using Next.js. This app will allow users to upload and share photos with a community. We will use Bootstrap for styling and localStorage to store the photos. The application will consist of two main pages: a home page to display the uploaded photos and an upload page to allow users to upload new photos.

Output Preview:

file
Output Preview

Prerequisites:

Approach

  • Set up a new Nextjs project with create-next-app.
  • Create a navigation bar with links to the home and upload pages.
  • Create a PhotoCard component to display individual photos with their title and description.
  • Create a PhtoGrid component to display a collection of photo cards.
  • Create a form to upload a new photo with a title and description.
  • Handle file input and save the photo data to local storage.
  • Display the uploaded photos using the PhotoGrid component.
  • Fetch photos from local storage and display them on the home page.

Steps to Create a Photo Sharing App Using Next.js:

Step 1: Initialized the Nextjs app.

npx create-next-app@latest photoSharing-app

Step 2: navigate to project directory.

cd photoSharing-app

Step 3: It will ask you some questions, so choose as the following.

√ Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... No
√ Would you like to use Tailwind CSS? ... No
√ Would you like to use `src/` directory? ... Yes
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@/*)? ... No

Step 4: Install the necessary package for your project using the following command.

npm i bootstrap

Project Structure:

Screenshot
Folder Structure

Dependencies

"dependencies": {
"autoprefixer": "^10.4.19",
"bootstrap": "^5.3.3",
"next": "14.1.3",
"react": "^18",
"react-dom": "^18",
}

Example: Create the required files and write the following code.

JavaScript
// src/app/page.js
'use client'
// import Header from '../components/Header';
import PhotoGrid from './components/PhotoGrid';
import { useEffect, useState } from 'react';
import Header from './components/Header';
import 'bootstrap/dist/css/bootstrap.min.css';


const Home = () => {
    const [photos, setPhotos] = useState([]);

    useEffect(() => {
        const storedPhotos = JSON.parse(localStorage.getItem('photos')) || [];
        setPhotos(storedPhotos);
    }, []);

    return (
        <div>
            <Header />
            <div className="container mt-4">
                <h1>Latest Photos</h1>
                <PhotoGrid photos={photos} />
            </div>
        </div>
    );
};

export default Home;
JavaScript
// src/app/components/Header.js

import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import Link from "next/link";

function Header() {
    return (
        <nav className="navbar navbar-expand-lg navbar-light bg-success shadow top-0">
            <div className="container">
                <p className="navbar-brand text-light" href="#">
                    PhotoApp
                </p>
                <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 href="/" passHref>
                                <p className="nav-link text-light"
                                style={{ fontSize: '1.25rem', textDecoration: 'none' }}>
                                    Home
                                </p>
                            </Link>
                        </li>
                        <li className="nav-item">
                            <Link href="/upload" passHref>
                                <p className="nav-link text-light"
                                style={{ fontSize: '1.25rem' }}>
                                    Upload Photo
                                </p>
                            </Link>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    );
}

export default Header;
JavaScript
// src/app/components/PhotoCard.js
const PhotoCard = ({ photo }) => (
    <div className="card mb-4">
        <img src={photo.url} className="card-img-top" alt={photo.title} />
        <div className="card-body">
            <h5 className="card-title">{photo.title}</h5>
            <p className="card-text">{photo.description}</p>
        </div>
    </div>
);

export default PhotoCard;
JavaScript
//src/app/components/PhotoGrid.js

'use client'
import PhotoCard from './PhotoCard';

const PhotoGrid = ({ photos }) => (
    <div className="row">
        {photos.map((photo) => (
            <div className="col-md-4" key={photo.id}>
                <PhotoCard photo={photo} />
            </div>
        ))}
    </div>
);

export default PhotoGrid;
JavaScript
// src/pages/upload.js

import Header from '../app/components/Header';
import { useState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

const Upload = () => {
    const [title, setTitle] = useState('');
    const [description, setDescription] = useState('');
    const [file, setFile] = useState(null);

    const handleSubmit = (e) => {
        e.preventDefault();
        const reader = new FileReader();
        reader.onloadend = () => {
            const newPhoto = {
                id: Date.now(),
                title,
                description,
                url: reader.result,
            };
            const storedPhotos = JSON.parse(localStorage.getItem('photos')) || [];
            storedPhotos.push(newPhoto);
            localStorage.setItem('photos', JSON.stringify(storedPhotos));
            alert('Photo uploaded successfully!');
            setTitle('');
            setDescription('');
            setFile(null);
        };
        if (file) {
            reader.readAsDataURL(file);
        }
    };

    return (
        <div>
            <Header />
            <div className="container mt-4">
                <div className="card shadow-sm">
                    <div className="card-body">
                        <h1 className="card-title">Upload a Photo</h1>
                        <form onSubmit={handleSubmit}>
                            <div className="form-group">
                                <label htmlFor="title">Title</label>
                                <input
                                    type="text"
                                    className="form-control"
                                    id="title"
                                    value={title}
                                    onChange={(e) => setTitle(e.target.value)}
                                    required
                                />
                            </div>
                            <div className="form-group">
                                <label htmlFor="description">Description</label>
                                <textarea
                                    className="form-control"
                                    id="description"
                                    value={description}
                                    onChange={(e) => setDescription(e.target.value)}
                                    required
                                />
                            </div>
                            <div className="form-group mt-2">
                                <label htmlFor="file">Photo</label>
                                <input
                                    type="file"
                                    className="form-control-file"
                                    id="file"
                                    onChange={(e) => setFile(e.target.files[0])}
                                    required
                                />
                            </div><br />
                            <button type="submit" className="btn btn-primary">
                                Upload
                            </button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    );
};

export default Upload;

Output:


Next Article

Similar Reads