Horje
Social Media Platform using MERN Stack

In web development, creating a “Social Media Website” will showcase and utilising the power of MERN stack – MongoDB, Express, React, and Node. This application will provide users the functionality to add a post, like the post and able to comment on it.

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

Prerequisites:

Approach to create Social Media Platform:

  • The social media website was developed with a dual focus on backend using Express.js and frontend using React.
  • Express handled API routes for CRUD operations, including likes and comments, and Multer facilitated file uploads for multimedia content.
  • React was chosen for the frontend, providing an interactive user interface with components for posts, likes, and comments.
  • Axios played a pivotal role in connecting the frontend to the backend API endpoints, ensuring smooth communication.
  • The integration phase involved configuring CORS, connecting frontend to backend API URLs, and thorough end-to-end testing for a seamless user experience.

Steps to Create the Project:

Step 1: Create a directory for the backend by running the following command.

npm init social_backend
cd social_backend

Step 2: Initialize the Express project and install the following dependencies.

npm init -y
npm install express mongoose cors body-parser multer uuid

Folder Structure(Backend):

ba

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

"dependencies": {
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"express": "^4.18.2",
"mongoose": "^8.0.3",
"multer": "^1.4.5-lts.1",
"uuid": "^9.0.1"
}

Example: Create the required files and add the following code:

JavaScript
// models/Post.js

const mongoose = require('mongoose');

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

const Post = mongoose.model('Post', postSchema);

module.exports = Post;
JavaScript
// server.js

const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');
const multer = require('multer');
const path = require('path');

const app = express();
const PORT = process.env.PORT || 5000;

app.use(cors());
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));

const storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, 'uploads/');
    },
    filename: function (req, file, cb) {
        cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
    }
});

const upload = multer({ storage: storage });

mongoose.connect('Your MongoDB connection string', { useNewUrlParser: true, useUnifiedTopology: true });

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

const Post = mongoose.model('Post', postSchema);

app.use(bodyParser.json());

app.get('/api/posts', async (req, res) => {
    try {
        const posts = await Post.find();
        res.json(posts);
    } catch (error) {
        res.status(500).json({ error: 'Internal Server Error' });
    }
});

app.post('/api/posts', upload.single('file'), async (req, res) => {
    try {
        const { title, content } = req.body;
        const file = req.file ? req.file.filename : undefined;

        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' });
    }
});

app.post('/api/posts/like/:postId', async (req, res) => {
    try {
        const postId = req.params.postId;
        const post = await Post.findById(postId);

        if (!post) {
            return res.status(404).json({ error: 'Post not found' });
        }

        post.likes += 1;
        await post.save();

        res.json(post);
    } catch (error) {
        console.error('Error liking post:', error);
        res.status(500).json({ error: 'Internal Server Error' });
    }
});

app.post('/api/posts/comment/:postId', async (req, res) => {
    try {
        const postId = req.params.postId;
        const { text } = req.body;
        const post = await Post.findById(postId);

        if (!post) {
            return res.status(404).json({ error: 'Post not found' });
        }

        post.comments.push({ text });
        await post.save();

        res.json(post);
    } catch (error) {
        console.error('Error adding comment:', error);
        res.status(500).json({ error: 'Internal Server Error' });
    }
});

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

Step 3: To start the backend run the following command.

node server.js

Step 4: Set up React frontend using the command.

npx create-react-app social_frontend
cd social_frontend

Step 5 : Installing the required packages:

npm i axios react-router-dom

Folder Structure(Frontend):

fr

The updated dependencies in package.json file of frontend will look lik:

"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^1.6.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.21.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Example: Create the required files and the following code.

CSS
/* App.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;
}
JavaScript
// App.js

import React from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import Home from './Home';
import CreatePost from './CreatePost';
import './App.css';

function App() {
    return (
        <Router>
            <div className="app">
                <nav>
                    <ul>
                        <li>
                            <Link to="/">Home</Link>
                        </li>
                        <li>
                            <Link to="/create">Create Post</Link>
                        </li>
                    </ul>
                </nav>
                <Routes>
                    <Route path="/create" element={<CreatePost />} />
                    <Route path="/" element={<Home />} />
                </Routes>
            </div>
        </Router>
    );
}

export default App;
JavaScript
// Home.js

import React, { useState, useEffect } from "react";
import axios from "axios";

function Home() {
    const [commentInput, setCommentInput] = useState("");
    const [posts, setPosts] = useState([]);

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

    const handleLike = (postId) => {
        axios
            .post(`http://localhost:5000/api/posts/like/${postId}`)
            .then((response) => {
                const updatedPosts = posts.map((post) =>
                    post._id === postId ? response.data : post
                );
                setPosts(updatedPosts);
            })
            .catch((error) => console.error("Error liking post:", error));
    };

    const handleAddComment = (postId, commentText) => {
        axios
            .post(`http://localhost:5000/api/posts/comment/${postId}`, {
                text: commentText,
            })
            .then((response) => {
                const updatedPosts = posts.map((post) =>
                    post._id === postId ? response.data : post
                );
                setPosts(updatedPosts);
            })
            .catch((error) => console.error("Error adding comment:", 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>
                            {post.file.includes(".mp4") ? (
                                <video width="320" height="240" controls>
                                    <source
                                        src={
                                    `http://localhost:5000/uploads/${post.file}`
                                        }
                                        type="video/mp4"
                                    />
                                    Your browser does not support the video tag.
                                </video>
                            ) : (
                                <img
                                    src={
                                    `http://localhost:5000/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>
            ))}
        </div>
    );
}

export default Home;
JavaScript
// CreatePost.js
import React, { useState } from "react";
import axios from "axios";

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

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

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

    const handlePostSubmit = () => {
        const formData = new FormData();
        formData.append("title", newPost.title);
        formData.append("content", newPost.content);
        formData.append("file", newPost.file);

        axios
            .post("http://localhost:5000/api/posts", formData)
            .then((response) => {
                setNewPost({ title: "", content: "", file: null });
            })
            .catch((error) => console.error("Error creating post:", error));
    };

    return (
        <div className="create-post">
            <h2>Create a Post</h2>
            <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" onChange={handleFileChange} />
            <button onClick={handlePostSubmit}>Post</button>
        </div>
    );
}

export default CreatePost;

Step 6: Start the application by running the following command.

npm start

Output:




Reffered: https://www.geeksforgeeks.org


Geeks Premier League

Related
Awesome Button Hover Effects in React Awesome Button Hover Effects in React
React Bootstrap Stacks React Bootstrap Stacks
Popular Agile Tools for Software Development Popular Agile Tools for Software Development
How to Start Google Maps in Satellite View How to Start Google Maps in Satellite View
Intensive and Extensive Properties - Definition &amp; Examples Intensive and Extensive Properties - Definition &amp; Examples

Type:
Geek
Category:
Coding
Sub Category:
Tutorial
Uploaded by:
Admin
Views:
13