Open In App

Social Networking Platform using Next.js

The Social Networking Platform built with NextJS is a web application that provides users the functionality to add a post, like a post, and be able to comment on it. The power of NextJS, a popular React framework for building server-side rendered (SSR) and statically generated web applications, this platform offers a seamless user experience with fast loading times and smooth navigation.

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

Screenshot-2024-03-20-000330

Prerequisites:

Approach to Create Social Networking Platform with NextJS:

Steps to Create the NextJS App:

Step 1: Set up a NextJS project using the following command.

npx create-next-app next-mern-project
cd next-mern-project

Step 2: Install required dependencies.

npm install axios mongoose 

Project Structure:

Screenshot-2024-03-19-235202

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

 "dependencies": {
"axios": "^1.6.8",
"mongodb": "^6.5.0",
"mongoose": "^8.2.2",
"multer": "^1.4.5-lts.1",
"next": "14.1.3",
"next-connect": "^1.0.0",
"react": "^18",
"react-dom": "^18",
"uuid": "^9.0.1"
}

Step 3: Creating a required files.

Example: Below is an example of creating a Social Networking Platform with NextJS.

/* globals.css */

.home {
    max-width: 800px;
    margin: 0 auto;
}

.post {
    border: 1px solid #ddd;
    padding: 15px;
    margin-bottom: 20px;
}

.post h3 {
    color: #333;
}

.post p {
    color: #555;
}

/* App.css */

.create-post {
    max-width: 600px;
    margin: 20px auto;
    padding: 20px;
    border: 1px solid #ddd;
    background-color: #fff;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

.create-post h2 {
    color: #333;
}

.create-post input,
.create-post textarea {
    width: 100%;
    margin: 10px 0;
    padding: 10px;
}

.create-post button {
    background-color: #4caf50;
    color: #fff;
    padding: 10px 15px;
    border: none;
    cursor: pointer;
}

.comment-input {
    margin-top: 10px;
    padding: 8px;
    width: 70%;
}

.comment-button {
    background-color: #4caf50;
    color: #fff;
    padding: 8px 16px;
    border: none;
    cursor: pointer;
}

.post img,
.post video {
    max-width: 100%;
    height: auto;
    margin-top: 10px;
}

.post button {
    background-color: #4caf50;
    color: #fff;
    padding: 8px 16px;
    border: none;
    cursor: pointer;
    margin-right: 10px;
}

.post ul {
    list-style: none;
    padding: 0;
}

.post li {
    margin-bottom: 5px;
}

.comment-input {
    margin-top: 10px;
    padding: 8px;
    width: 70%;
}

.comment-button {
    background-color: #4caf50;
    color: #fff;
    padding: 8px 16px;
    border: none;
    cursor: pointer;
}


/* App.css */

.app {
    max-width: 800px;
    margin: 0 auto;
}

nav {
    background-color: #333;
    padding: 10px;
}

nav ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

nav li {
    display: inline-block;
    margin-right: 20px;
}

nav a {
    text-decoration: none;
    color: #fff;
    font-weight: bold;
    font-size: 16px;
}

nav a:hover {
    color: #4caf50;
}

.create-post,
.home {
    border: 1px solid #ddd;
    padding: 20px;
    margin-bottom: 20px;
    background-color: #fff;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

.home h2,
.create-post h2 {
    color: #333;
}

.home .post,
.create-post {
    margin-bottom: 30px;
}

.home .post button,
.create-post button {
    background-color: #4caf50;
    color: #fff;
    padding: 10px 15px;
    border: none;
    cursor: pointer;
}

.home .post button:hover,
.create-post button:hover {
    background-color: #45a049;
}
//pages/index.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function Home() {
    const [posts, setPosts] = useState([]);
    const [commentText, setCommentText] = useState('');

    useEffect(() => {
        axios
            .get('/api/posts')
            .then((response) => setPosts(response.data))
            .catch((error) => console.error(
                'Error fetching posts:', error));
    }, []);

    const handleLike = async (id) => {
        try {
            const response = await axios.put('/api/posts', {
                id, action: 'like'
            });
            setPosts(posts.map(
                (post) => (post._id === id ? response.data : post)));
        } catch (error) {
            console.error('Error liking post:', error);
        }
    };

    const handleComment = async (id, text) => {
        try {
            const response = await axios.put('/api/posts', {
                id, action: 'comment', text
            });
            setPosts(posts.map(
                (post) => (post._id === id ? response.data : post)));
            setCommentText(''); // Reset comment text after posting
        } catch (error) {
            console.error('Error commenting on post:', error);
        }
    };

    const convertImageToBase64 = async (file) => {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = () => resolve(reader.result);
            reader.onerror = (error) => reject(error);
        });
    };

    return (
        <div className="home">
            <h2>Recent Posts</h2>
            {posts.map((post) => (
                <div key={post._id} className="post">
                    <h3>{post.title}</h3>
                    <p>{post.content}</p>
                    {post.file && (
                        <div>
                            <img src={post.file} alt="Post" />
                        </div>
                    )}
                    <p>Likes: {post.likes}</p>
                    <button onClick={() => handleLike(post._id)}>
                        Like
                    </button>
                    <p>Comments: {post.comments.length}</p>
                    <ul>
                        {post.comments.map((comment, index) => (
                            <li key={index}>{comment.text}</li>
                        ))}
                    </ul>
                    <div>
                        <input type="text" placeholder="Write a comment..."
                            value={commentText}
                            onChange={(e) => setCommentText(e.target.value)} />
                        <button
                            onClick={() => handleComment(post._id, commentText)}>
                            Comment
                        </button>
                    </div>
                </div>
            ))}
        </div>
    );
}

export default Home;
// pages/_app.js

import '../styles/globals.css';
import React from 'react';
import { useRouter } from 'next/router';

function MyApp({ Component, pageProps }) {
    const router = useRouter();

    return (
        <div className="app">
            <nav>
                <ul>
                    <li>
                        <button onClick={() => router.push('/')}>
                            Home
                        </button>
                    </li>
                    <li>
                        <button onClick={() => router.push('/create')}>
                            Create Post
                        </button>
                    </li>
                </ul>
            </nav>
            <Component {...pageProps} />
        </div>
    );
}

export default MyApp;
// pages/create.js

import React, { useState } from 'react';
import axios from 'axios';

function CreatePost() {
    const [newPost, setNewPost] = useState({
        title: '',
        content: '',
        file: null
    });
    const [error, setError] = useState('');

    const handleInputChange = event => {
        const { name, value } = event.target;
        setNewPost({ ...newPost, [name]: value });
    };

    const handleFileChange = event => {
        setNewPost({
            ...newPost,
            file: event.target.files[0]
        });
    };

    const handlePostSubmit = async () => {
        try {
            const { title, content, file } = newPost;

            if (!title || !content) {
                setError('Title and content are required fields.');
                return;
            }

            const postData = { title, content };

            const response = await axios.post('/api/posts',
                postData);
            console.log('Post created:', response.data);
            setNewPost({ title: '', content: '', file: null });
            setError('');
        } catch (error) {
            console.error('Error creating post:', error);
            setError('Error creating post. Please try again.');
        }
    };


    return (
        <div className="create-post">
            <h2>Create a Post</h2>
            {error && <p style={{ color: 'red' }}>{error}</p>}
            <input type="text" name="title"
                placeholder="Title" value={newPost.title}
                onChange={handleInputChange} />
            <textarea name="content"
                placeholder="Content" value={newPost.content}
                onChange={handleInputChange}>
            </textarea>
            <input type="file" name="file"
                accept="image/*" onChange={handleFileChange} />
            <button onClick={handlePostSubmit}>
                Post
            </button>
        </div>
    );
}

export default CreatePost;
//pages/api/posts.js
import mongoose from 'mongoose';

// MongoDB connection URI
const MONGODB_URI = 'Your Mongo Database URL Here';

// Connect to MongoDB
mongoose.connect(MONGODB_URI, {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

// Define post schema
const postSchema = new mongoose.Schema({
    title: String,
    content: String,
    file: String,
    likes: { type: Number, default: 0 },
    comments: [{ text: String }]
});

// Define Post model
const Post = mongoose.models.Post || mongoose.model('Post', postSchema);

// Export API handler
export default async function handler(req, res) {
    if (req.method === 'GET') {
        try {
            const posts = await Post.find();
            res.status(200).json(posts);
        } catch (error) {
            res.status(500).json({
                error: 'Internal Server Error'
            });
        }
    } else if (req.method === 'POST') {
        try {
            const { title, content, file } = req.body;

            if (!title || !content) {
                return res.status(400).json({
                    error: 'Title and content are required fields'
                });
            }

            const post = new Post({ title, content, file });
            await post.save();
            res.status(201).json(post);
        } catch (error) {
            console.error('Error creating post:', error);
            res.status(500).json({
                error: 'Internal Server Error'
            });
        }
    } else if (req.method === 'PUT') {
        try {
            const { id, action } = req.body;

            if (!id || !action) {
                return res.status(400).json({
                    error: 'Post ID and action are required'
                });
            }

            let updatedPost;

            if (action === 'like') {
                updatedPost = await Post.findByIdAndUpdate(id,
                    { $inc: { likes: 1 } }, { new: true });
            } else if (action === 'comment') {
                const { text } = req.body;
                if (!text) {
                    return res.status(400).json({
                        error: 'Comment text is required'
                    });
                }
                updatedPost = await Post.findByIdAndUpdate(id,
                    { $push: { comments: { text } } }, { new: true });
            } else {
                return res.status(400).json({
                    error: 'Invalid action'
                });
            }

            res.status(200).json(updatedPost);
        } catch (error) {
            console.error('Error updating post:', error);
            res.status(500).json({
                error: 'Internal Server Error'
            });
        }
    } else {
        res.status(405).end(); // Method Not Allowed
    }
}
// components/Post.js

import React, { useState } from 'react';
import axios from 'axios';

function Post({ post }) {
    const [commentInput, setCommentInput] = useState('');

    const handleLike = postId => {
        axios.post(`/api/posts/like/${postId}`)
            .then(response => {
                // Handle updated post data
            })
            .catch(
                error => console.error('Error liking post:', error));
    };

    const handleAddComment = (postId, commentText) => {
        axios.post(`/api/posts/comment/${postId}`,
            { text: commentText })
            .then(response => {
                // Handle updated post data
            })
            .catch(
                error => console.error('Error adding comment:', error));
    };

    return (
        <div className="post">
            <h3>{post.title}</h3>
            <p>{post.content}</p>
            {post.file && (
                <div>
                    <img src={`/uploads/${post.file}`}
                        alt="Post Media" />
                </div>
            )}
            <p>Likes: {post.likes}</p>
            <button
                onClick={() => handleLike(post._id)}>
                Like
            </button>
            <p>Comments: {post.comments.length}</p>
            <ul>
                {post.comments.map((comment, index) => (
                    <li key={index}>{comment.text}</li>
                ))}
            </ul>
            <input type="text" placeholder="Add a comment"
                className="comment-input"
                onChange={(e) => setCommentInput(e.target.value)} />
            <button
                onClick={() => handleAddComment(post._id, commentInput)}
                className="comment-button">
                Add Comment
            </button>
        </div>
    );
}

export default Post;

Start your application using the following command.

npm run dev

Output:

aa

Database records:

Screenshot-2024-03-20-000736


Article Tags :