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.

File and Folder Organization

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
- Setting up the vite app:
npm create vite@latest social-media-dashboard
cd social-media-dashboard - Install dependencies:
npm install - Run the development server:
npm run dev - Access the app:
Open http://localhost:5173 in your browser.
Code base
Files in:-
- src/components
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>
)
}
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>
)
}
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>
)
}
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>
)
}
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
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)
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
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
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 />
}
}
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>
)
}
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>
)
}
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
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
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
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>,
)
@import "tailwindcss";
- base folder->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.