Social Media Dashboard (React Based Project)

Last Updated : 19 Aug, 2025

Here is a Social Media Dashboard, a React-based web app that brings together all your social media statistics in one place. It shows important data like followers, likes, comments, and engagement in a clean and interactive interface. Built with React, the dashboard is fast, responsive, and easy to customize with widgets and real-time updates.

Social_Media_Output

File and Folder Organization

File_Folder_Structure_Social_Media

Key Folders

  • src/: Main source code.
    • components/: Reusable UI elements.
    • contexts/: React Contexts for global state (auth, theme).
    • hooks/: Custom React hooks.
    • pages/: Route-based pages.
    • store/: Redux store and reducers.
  • public files: index.html for the app entry point.
  • config files: ESLint, Vite, and package management.

Setup

  1. Setting up the vite app:
    npm create vite@latest social-media-dashboard
    cd social-media-dashboard
  2. Install dependencies:
    npm install
  3. Run the development server:
    npm run dev
  4. Access the app:
    Open http://localhost:5173 in your browser.

Code base

Files in:-

  • src/components
Navbar.jsx
import React, { useContext } from 'react' // Update import
import { Link } from 'react-router-dom'
import { useAuth } from '../contexts/AuthContext.jsx'
import { ThemeContext } from '../contexts/ThemeContext.jsx'

export default function Navbar() {
  const { user, logout } = useAuth()
  const { theme } = useContext(ThemeContext)

  return (
    <nav className="bg-blue-500 p-4 text-white flex justify-between">
      <div>
        <Link to="/feed" className="mr-4">Feed</Link>
        <Link to="/profile" className="mr-4">Profile</Link>
        <Link to="/settings">Settings</Link>
      </div>
      <div>
        {user ? (
          <button onClick={logout}>Logout</button>
        ) : (
          <Link to="/login">Login</Link>
        )}
        <span className="ml-4">Theme: {theme}</span>
      </div>
    </nav>
  )
}
PostForm.jsx
import React, { useState } from 'react' // Update import
import { useDispatch } from 'react-redux'
import { addPost } from '../store/index.js'
import { useAuth } from '../contexts/AuthContext.jsx'

export default function PostForm() {
  const [title, setTitle] = useState('')
  const [body, setBody] = useState('')
  const dispatch = useDispatch()
  const { user } = useAuth()

  const isValid = title.length > 5 && body.length > 10

  const handleSubmit = (e) => {
    e.preventDefault()
    if (isValid) {
      dispatch(addPost({ id: Date.now(), title, body, userId: user.username }))
      setTitle('')
      setBody('')
    }
  }

  return (
    <form onSubmit={handleSubmit} className="mb-4">
      <input
        type="text"
        value={title}
        onChange={(e) => setTitle(e.target.value)}
        placeholder="Title"
        className="border p-2 mb-2 w-full text-black"
      />
      <textarea
        value={body}
        onChange={(e) => setBody(e.target.value)}
        placeholder="What's on your mind?"
        className="border p-2 w-full text-black"
      />
      <button type="submit" disabled={!isValid} className="bg-blue-500 text-white p-2 disabled:opacity-50">
        Post
      </button>
    </form>
  )
}
ToDoList.jsx
import React, { useState } from 'react' // Update import

export default function ToDoList() {
  const [tasks, setTasks] = useState([])
  const [taskText, setTaskText] = useState('')
  const [count, setCount] = useState(0)

  const addTask = () => {
    if (taskText) {
      setTasks([...tasks, taskText])
      setTaskText('')
      setCount(count + 1)
    }
  }

  return (
    <div className="mt-4">
      <h4>User Goals (ToDo)</h4>
      <input
        type="text"
        value={taskText}
        onChange={(e) => setTaskText(e.target.value)}
        placeholder="Add goal"
        className="border p-1 text-black"
      />
      <button onClick={addTask} className="bg-green-500 text-white p-1 ml-2">Add</button>
      <ul>
        {tasks.map((task, i) => <li key={i}>{task}</li>)}
      </ul>
      <p>Tasks added: {count}</p>
    </div>
  )
}
Post.jsx
import React, { useState } from 'react' // Update import
import { useDispatch } from 'react-redux'
import { likePost, addComment } from '../store/index.js'

export default function Post({ post }) {
  const dispatch = useDispatch()
  const [commentText, setCommentText] = useState('')

  const handleLike = () => {
    dispatch(likePost(post.id))
  }

  const handleCommentSubmit = (e) => {
    e.preventDefault()
    if (commentText) {
      dispatch(addComment(post.id, commentText))
      setCommentText('')
    }
  }

  return (
    <div className="bg-gray-100 dark:bg-gray-800 p-4 mb-4 rounded">
      <h3 className="font-bold">{post.title}</h3>
      <p>{post.body}</p>
      <button onClick={handleLike} className="bg-green-500 text-white p-1 mr-2">
        Like ({post.likes || 0})
      </button>
      <form onSubmit={handleCommentSubmit}>
        <input
          type="text"
          value={commentText}
          onChange={(e) => setCommentText(e.target.value)}
          placeholder="Add comment"
          className="border p-1 text-black"
        />
        <button type="submit" className="bg-blue-500 text-white p-1">Comment</button>
      </form>
      <ul>
        {post.comments?.map((c, i) => <li key={i}>{c}</li>)}
      </ul>
    </div>
  )
}
ProfileCard.jsx
import React from 'react' // Add import

export default function ProfileCard({ user }) {
  return (
  <div className="bg-gray-100 p-4 rounded">
      <h3 className="font-bold">{user.name}</h3>
      <p>@{user.username}</p>
      <p>Email: {user.email}</p>
    </div>
  )
}
  • src/contexts
AuthContext.jsx
import React, { createContext, useContext, useState } from 'react' // Update import

const AuthContext = createContext()

export default function AuthProvider({ children }) {
  const [user, setUser] = useState(null)

  const login = (username, password) => {
    if (username && password) {
      setUser({ username })
    }
  }

  const logout = () => {
    setUser(null)
  }

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  )
}

export const useAuth = () => useContext(AuthContext)
ThemeContext.jsx
import React, { createContext, useState } from 'react'

export const ThemeContext = createContext()

export default function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light')

  const toggleTheme = () => {
    setTheme((prev) => {
      const newTheme = prev === 'light' ? 'dark' : 'light'
      document.documentElement.classList.toggle('dark', newTheme === 'dark')
      return newTheme
    })
  }

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  )
}
  • src/hooks->usePosts.js
usePosts.js
import React, { useEffect } from 'react' // Add import
import { useDispatch, useSelector } from 'react-redux'
import { setPosts } from '../store/index.js'

export const usePosts = () => {
  const dispatch = useDispatch()
  const posts = useSelector((state) => state.posts)

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts?_limit=10')
      .then((res) => res.json())
      .then((data) => dispatch(setPosts(data.map((p) => ({ ...p, likes: 0, comments: [] })))))
  }, [dispatch])

  return posts
}
  • src/pages
Feed.jsx
import React, { Component } from 'react' // Update import
import { useDispatch, useSelector } from 'react-redux'
import Post from '../components/Post.jsx'
import PostForm from '../components/PostForm.jsx'
import { setUsers } from '../store/index.js'
import { usePosts } from '../hooks/usePosts.js'

// Functional wrapper for hooks
function FeedContent() {
  const posts = usePosts()
  const dispatch = useDispatch()

  React.useEffect(() => { // Use React.useEffect
    fetch('https://jsonplaceholder.typicode.com/users?_limit=5')
      .then((res) => res.json())
      .then((data) => dispatch(setUsers(data)))

    const handleScroll = () => {
      if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
        console.log('Load more posts...')
      }
    }
    window.addEventListener('scroll', handleScroll)
    return () => window.removeEventListener('scroll', handleScroll)
  }, [dispatch])

  return (
    <div className="p-4 max-w-2xl mx-auto">
      <PostForm />
      <div>
        {posts.map((post) => (
          <Post key={post.id} post={post} />
        ))}
      </div>
    </div>
  )
}

export default class Feed extends Component {
  componentDidMount() {
    this.interval = setInterval(() => {
      console.log('Checking for new posts...')
    }, 5000)
  }

  componentWillUnmount() {
    clearInterval(this.interval)
  }

  render() {
    return <FeedContent />
  }
}
Login.jsx
import React, { useState } from 'react' // Update import
import { useAuth } from '../contexts/AuthContext.jsx'
import { useNavigate } from 'react-router-dom'

export default function Login() {
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  const { login } = useAuth()
  const navigate = useNavigate()

  const handleLogin = (e) => {
    e.preventDefault()
    login(username, password)
    navigate('/feed')
  }

  return (
    <div className="p-4 max-w-md mx-auto">
      <h2>Login</h2>
      <form onSubmit={handleLogin}>
        <input
          type="text"
          value={username}
          onChange={(e) => setUsername(e.target.value)}
          placeholder="Username"
          className="border p-2 mb-2 w-full text-black"
        />
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          placeholder="Password"
          className="border p-2 mb-2 w-full text-black"
        />
        <button type="submit" className="bg-blue-500 text-white p-2">Login</button>
      </form>
    </div>
  )
}
Profile.jsx
import React, { useEffect } from 'react' // Update import
import { useDispatch, useSelector } from 'react-redux'
import { followUser } from '../store/index.js'
import ProfileCard from '../components/ProfileCard.jsx'
import ToDoList from '../components/ToDoList.jsx'

export default function Profile() {
  const users = useSelector((state) => state.users)
  const dispatch = useDispatch()

  useEffect(() => {
    // Users already fetched in Feed
  }, [])

  return (
    <div className="p-4">
      <h2>Profile</h2>
      <ToDoList />
      <h3>Users to Follow</h3>
      <div className="grid grid-cols-2 gap-4">
        {users.map((user) => (
          <div key={user.id}>
            <ProfileCard user={user} />
            <button
              onClick={() => dispatch(followUser(user.id))}
              className="bg-blue-500 text-white p-1"
              disabled={user.followed}
            >
              {user.followed ? 'Followed' : 'Follow'}
            </button>
          </div>
        ))}
      </div>
    </div>
  )
}
Settings.jsx
import React, { useContext } from 'react'
import { ThemeContext } from '../contexts/ThemeContext.jsx'

export default function Settings() {
  const { toggleTheme } = useContext(ThemeContext)

  return (
    <div className="p-4">
      <h2>Settings</h2>
      <button onClick={toggleTheme} className="bg-purple-500 text-white p-2">
        Toggle Theme
      </button>
    </div>
  )
}
  • src/store->index.js
store/index.js
import { createStore, combineReducers } from 'redux'

// Actions
export const addPost = (post) => ({ type: 'ADD_POST', payload: post })
export const likePost = (postId) => ({ type: 'LIKE_POST', payload: postId })
export const addComment = (postId, comment) => ({ type: 'ADD_COMMENT', payload: { postId, comment } })
export const followUser = (userId) => ({ type: 'FOLLOW_USER', payload: userId })
export const setPosts = (posts) => ({ type: 'SET_POSTS', payload: posts })
export const setUsers = (users) => ({ type: 'SET_USERS', payload: users })

// Reducers
const postsReducer = (state = [], action) => {
  switch (action.type) {
    case 'SET_POSTS':
      return action.payload
    case 'ADD_POST':
      return [action.payload, ...state]
    case 'LIKE_POST':
      return state.map((post) =>
        post.id === action.payload ? { ...post, likes: (post.likes || 0) + 1 } : post
      )
    case 'ADD_COMMENT':
      return state.map((post) =>
        post.id === action.payload.postId
          ? { ...post, comments: [...(post.comments || []), action.payload.comment] }
          : post
      )
    default:
      return state
  }
}

const usersReducer = (state = [], action) => {
  switch (action.type) {
    case 'SET_USERS':
      return action.payload
    case 'FOLLOW_USER':
      return state.map((user) =>
        user.id === action.payload ? { ...user, followed: true } : user
      )
    default:
      return state
  }
}

const rootReducer = combineReducers({
  posts: postsReducer,
  users: usersReducer,
})

const store = createStore(rootReducer)

export default store
  • src
App.jsx
import React from 'react' // Add this import
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'
import { Provider } from 'react-redux'
import store from './store/index.js'
import ThemeProvider from './contexts/ThemeContext.jsx'
import AuthProvider, { useAuth } from './contexts/AuthContext.jsx'
import Navbar from './components/Navbar.jsx'
import Feed from './pages/Feed.jsx'
import Profile from './pages/Profile.jsx'
import Settings from './pages/Settings.jsx'
import Login from './pages/Login.jsx'

// ProtectedRoute component for authentication
const ProtectedRoute = ({ children }) => {
  const { user } = useAuth()
  return user ? children : <Navigate to="/login" />
}

function App() {
  return (
    <Provider store={store}>
      <ThemeProvider>
        <AuthProvider>
          <Router>
            <div className="min-h-screen">
              <Navbar />
              <Routes>
                <Route path="/login" element={<Login />} />
                <Route path="/feed" element={<ProtectedRoute><Feed /></ProtectedRoute>} />
                <Route path="/profile" element={<ProtectedRoute><Profile /></ProtectedRoute>} />
                <Route path="/settings" element={<ProtectedRoute><Settings /></ProtectedRoute>} />
                <Route path="*" element={<Navigate to="/login" />} />
              </Routes>
            </div>
          </Router>
        </AuthProvider>
      </ThemeProvider>
    </Provider>
  )
}

export default App
main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)
index.css
@import "tailwindcss";
  • base folder->index.html
index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Social Media Dashboard</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

Core Files Explained

Entry Point

  • main.jsx: Renders the root React component (App) into the DOM.

App Component

  • App.jsx: Sets up routing, Redux provider, theme, and authentication contexts. Uses React Router for navigation and protects routes with authentication.

Styling

  • index.css: Uses Tailwind CSS for utility-first styling, supporting light/dark themes.
  • App.css: Additional custom styles.

State Management

  • index.js: Implements Redux store with actions and reducers for posts and users.

Contexts

  • AuthContext.jsx: Manages authentication state.
  • ThemeContext.jsx: Manages theme switching.

Custom Hooks

  • usePosts.js: Fetches posts from an API and syncs with Redux.

Components

  • Navbar.jsx: Navigation bar with theme and auth controls.
  • Post.jsx: Displays a post, handles likes and comments.
  • PostForm.jsx: Form to create new posts.
  • ProfileCard.jsx: Displays user profile info.
  • ToDoList.jsx: Simple to-do list for user goals.

Pages

  • Feed.jsx: Main feed, shows posts and post form.
  • Profile.jsx: User profile, list of users to follow, and to-do list.
  • Login.jsx: Login form.
  • Settings.jsx: Theme toggle.

Coding Highlights

  • React Functional Components: Most UI is built with functional components and hooks.
  • Redux: Centralized state for posts and users.
  • React Context: Used for authentication and theme management.
  • Routing: Protected routes using React Router and custom logic.
  • Tailwind CSS: Rapid styling with utility classes.
  • API Integration: Fetches posts and users from jsonplaceholder.typicode.com.
Comment