Skip to content

A modern, full-featured blogging platform built with Next.js 14, featuring authentication, rich text editing, comments, categories, and dark mode support. This project demonstrates best practices in React, Next.js App Router, Prisma ORM, MongoDB, and NextAuth.js.

Notifications You must be signed in to change notification settings

arnobt78/Blogging-Platform--NextJS-FullStack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Blog App - Full-Stack Next.js, Prisma, MongoDB, Firebase Blogging Platform

A modern, full-featured blogging platform built with Next.js 14, featuring authentication, rich text editing, comments, categories, and dark mode support. This project demonstrates best practices in React, Next.js App Router, Prisma ORM, MongoDB, and NextAuth.js.


πŸ“‹ Table of Contents


🎯 Overview

This is a complete blogging platform where users can:

  • Read blog posts across multiple categories (Style, Fashion, Food, Travel, Culture, Coding)
  • Create new blog posts with rich text editor and image uploads
  • Comment on posts (requires authentication)
  • Authenticate using Google OAuth or GitHub OAuth
  • Browse posts by category with pagination
  • Experience dark/light theme toggle

The application uses Next.js 14 App Router for server-side rendering, Prisma ORM with MongoDB for data persistence, NextAuth.js for authentication, Firebase Storage for image uploads, and React Quill for rich text editing.


✨ Features

Core Features

  • βœ… User Authentication - Google & GitHub OAuth integration
  • βœ… Blog Post Management - Create, read, and view posts
  • βœ… Rich Text Editor - React Quill with HTML content support
  • βœ… Image Upload - Firebase Storage integration for post images
  • βœ… Comments System - Authenticated users can comment on posts
  • βœ… Category Filtering - Browse posts by category (Style, Fashion, Food, Travel, Culture, Coding)
  • βœ… Pagination - Navigate through multiple pages of posts
  • βœ… Dark Mode - Toggle between light and dark themes
  • βœ… View Counter - Track post views automatically
  • βœ… SEO Optimized - Dynamic metadata generation for all pages
  • βœ… Responsive Design - Mobile-first responsive layout

Technical Features

  • βœ… Server Components - Leverages Next.js 14 App Router for optimal performance
  • βœ… API Routes - RESTful API endpoints for data operations
  • βœ… Database Transactions - Atomic operations for data consistency
  • βœ… Image Optimization - Next.js Image component with automatic optimization
  • βœ… Type Safety - Prisma schema ensures type-safe database queries
  • βœ… Session Management - Secure session handling with NextAuth.js

πŸ›  Tech Stack

Frontend

  • Next.js 14.2.35 - React framework with App Router
  • React 18.3.1 - UI library
  • CSS Modules - Scoped styling
  • React Quill 2.0.0 - Rich text editor
  • SWR 2.2.2 - Data fetching and caching

Backend

  • Next.js API Routes - Serverless API endpoints
  • Prisma 5.2.0 - Type-safe ORM
  • MongoDB - NoSQL database
  • NextAuth.js 4.23.1 - Authentication library

Services & Tools

  • Firebase Storage - Image hosting
  • Google OAuth - Authentication provider
  • GitHub OAuth - Authentication provider
  • TypeScript/TSX - Type checking for seed scripts

πŸ“ Project Structure

lamablog/
β”œβ”€β”€ prisma/
β”‚   β”œβ”€β”€ schema.prisma          # Database schema definition
β”‚   └── seed.ts                # Database seeding script
β”œβ”€β”€ public/                     # Static assets (images, icons)
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app/                    # Next.js App Router pages
β”‚   β”‚   β”œβ”€β”€ api/                # API routes
β”‚   β”‚   β”‚   β”œβ”€β”€ auth/
β”‚   β”‚   β”‚   β”‚   └── [...nextauth]/route.js
β”‚   β”‚   β”‚   β”œβ”€β”€ posts/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ route.js   # GET, POST /api/posts
β”‚   β”‚   β”‚   β”‚   └── [slug]/route.js  # GET /api/posts/[slug]
β”‚   β”‚   β”‚   β”œβ”€β”€ categories/route.js
β”‚   β”‚   β”‚   └── comments/route.js
β”‚   β”‚   β”œβ”€β”€ blog/page.jsx       # Blog listing page
β”‚   β”‚   β”œβ”€β”€ posts/[slug]/page.jsx  # Single post page
β”‚   β”‚   β”œβ”€β”€ write/page.jsx     # Create post page
β”‚   β”‚   β”œβ”€β”€ login/page.jsx      # Login page
β”‚   β”‚   β”œβ”€β”€ page.jsx            # Homepage
β”‚   β”‚   β”œβ”€β”€ layout.js           # Root layout
β”‚   β”‚   └── globals.css         # Global styles
β”‚   β”œβ”€β”€ components/             # Reusable React components
β”‚   β”‚   β”œβ”€β”€ navbar/
β”‚   β”‚   β”œβ”€β”€ footer/
β”‚   β”‚   β”œβ”€β”€ card/
β”‚   β”‚   β”œβ”€β”€ cardList/
β”‚   β”‚   β”œβ”€β”€ categoryList/
β”‚   β”‚   β”œβ”€β”€ featured/
β”‚   β”‚   β”œβ”€β”€ comments/
β”‚   β”‚   β”œβ”€β”€ pagination/
β”‚   β”‚   β”œβ”€β”€ authLinks/
β”‚   β”‚   β”œβ”€β”€ themeToggle/
β”‚   β”‚   └── Menu/
β”‚   β”œβ”€β”€ context/
β”‚   β”‚   └── ThemeContext.jsx     # Theme state management
β”‚   β”œβ”€β”€ providers/
β”‚   β”‚   β”œβ”€β”€ AuthProvider.jsx    # NextAuth session provider
β”‚   β”‚   └── ThemeProvider.jsx   # Theme class provider
β”‚   └── utils/
β”‚       β”œβ”€β”€ connect.js          # Prisma client singleton
β”‚       β”œβ”€β”€ auth.js             # NextAuth configuration
β”‚       └── firebase.js          # Firebase configuration
β”œβ”€β”€ .env                        # Environment variables
β”œβ”€β”€ next.config.js              # Next.js configuration
β”œβ”€β”€ package.json                # Dependencies and scripts
└── README.md                   # This file

πŸš€ Getting Started

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn package manager
  • MongoDB database (local or remote)
  • Google OAuth credentials (for authentication)
  • Firebase project (for image storage)

Installation

  1. Clone the repository
git clone <repository-url>
cd lamablog
  1. Install dependencies
npm install
  1. Set up environment variables (see Environment Variables section)

  2. Set up the database (see Database Setup section)

  3. Run the development server

npm run dev
  1. Open your browser

Navigate to http://localhost:3000


πŸ” Environment Variables

Create a .env file in the root directory with the following variables:

Required Variables

# Database Connection
DATABASE_URL=mongodb://username:password@host:port/database?authSource=database&replicaSet=rs0

# NextAuth Configuration
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key-here

# Google OAuth (for authentication)
GOOGLE_ID=your-google-client-id
GOOGLE_SECRET=your-google-client-secret

# GitHub OAuth (optional, for GitHub login)
GITHUB_ID=your-github-client-id
GITHUB_SECRET=your-github-client-secret

# Firebase Configuration (for image uploads)
FIREBASE=your-firebase-api-key

# Site URL (for production)
NEXT_PUBLIC_SITE_URL=https://your-domain.com

How to Obtain Each Variable

1. DATABASE_URL

For MongoDB Atlas (Cloud):

mongodb+srv://username:password@cluster.mongodb.net/database?retryWrites=true&w=majority

For Local MongoDB:

mongodb://localhost:27017/database

For Self-Hosted VPS MongoDB:

mongodb://username:password@your-vps-ip:port/database?authSource=database&replicaSet=rs0

2. NEXTAUTH_SECRET

Generate a random secret:

openssl rand -base64 32

Or use an online generator: https://generate-secret.vercel.app/32

3. GOOGLE_ID & GOOGLE_SECRET

  1. Go to Google Cloud Console
  2. Create a new project or select existing
  3. Enable Google+ API
  4. Go to Credentials β†’ Create Credentials β†’ OAuth 2.0 Client ID
  5. Configure consent screen
  6. Add authorized redirect URI: http://localhost:3000/api/auth/callback/google
  7. Copy Client ID and Client Secret

4. GITHUB_ID & GITHUB_SECRET

  1. Go to GitHub Developer Settings
  2. Click New OAuth App
  3. Fill in:
    • Application name: Your app name
    • Homepage URL: http://localhost:3000
    • Authorization callback URL: http://localhost:3000/api/auth/callback/github
  4. Copy Client ID and generate Client Secret

5. FIREBASE

  1. Go to Firebase Console
  2. Create a new project
  3. Go to Project Settings β†’ General
  4. Scroll to Your apps section
  5. Click Web icon to add Firebase to your web app
  6. Copy the apiKey from the config object

6. NEXT_PUBLIC_SITE_URL

  • Development: http://localhost:3000
  • Production: Your production domain (e.g., https://yourdomain.com)

πŸ—„ Database Setup

1. Install Prisma CLI (if not already installed)

npm install -g prisma

2. Generate Prisma Client

npx prisma generate

3. Push Schema to Database

MongoDB doesn't use migrations like SQL databases. Instead, use db push:

npx prisma db push

This will:

  • Create collections (tables) in MongoDB
  • Create indexes as defined in schema
  • Set up relationships between collections

4. Seed the Database (Optional)

If you have seed data, run:

npm run db:seed

This will populate your database with initial data (categories, sample posts, etc.).

Database Schema Overview

The application uses the following MongoDB collections:

  • User - User accounts (from NextAuth)
  • Account - OAuth account links
  • Session - User sessions
  • Post - Blog posts
  • Category - Post categories
  • Comment - Post comments
  • VerificationToken - Email verification tokens

πŸƒ Running the Project

Development Mode

npm run dev

Starts the development server at http://localhost:3000

Production Build

npm run build
npm start

Other Commands

# Lint code
npm run lint

# Seed database
npm run db:seed

# Open Prisma Studio (database GUI)
npx prisma studio

🧩 Components Documentation

Layout Components

Navbar (src/components/navbar/Navbar.jsx)

Purpose: Main navigation bar with links and authentication buttons.

Features:

  • Social media icons
  • Logo/brand name
  • Navigation links (Homepage, Contact, About)
  • Theme toggle
  • Authentication links (Login/Logout)

Usage:

import Navbar from "@/components/navbar/Navbar";

// Automatically included in root layout

Reusability: Can be customized by modifying navbar.module.css for styling.


Footer (src/components/footer/Footer.jsx)

Purpose: Site footer with copyright and links.

Usage:

import Footer from "@/components/footer/Footer";

// Automatically included in root layout

Content Components

Card (src/components/card/Card.jsx)

Purpose: Displays a single blog post card with image, title, description, and link.

Props:

  • item (object) - Post data object
  • priority (boolean, optional) - Prioritize image loading for LCP optimization

Usage:

import Card from "@/components/card/Card";

<Card item={post} priority={index === 0} />;

Reusability: Perfect for any post listing page. Modify card.module.css for custom styling.


CardList (src/components/cardList/CardList.jsx)

Purpose: Server component that displays a paginated list of blog post cards.

Props:

  • page (number) - Current page number
  • cat (string, optional) - Category filter

Usage:

import CardList from "@/components/cardList/CardList";

<CardList page={1} cat="style" />;

Reusability: Can be used on any page that needs to display a list of posts. Modify the API endpoint URL if using a different data source.


Featured (src/components/featured/Featured.jsx)

Purpose: Hero section displaying a featured blog post on the homepage.

Usage:

import Featured from "@/components/featured/Featured";

<Featured />;

Reusability: Customize the featured post by modifying the component to fetch from an API or use static content.


CategoryList (src/components/categoryList/CategoryList.jsx)

Purpose: Server component displaying all available blog categories.

Usage:

import CategoryList from "@/components/categoryList/CategoryList";

<CategoryList />;

Reusability: Can be used anywhere categories need to be displayed. The component fetches from /api/categories.


Comments (src/components/comments/Comments.jsx)

Purpose: Client component for displaying and creating comments on blog posts.

Props:

  • postSlug (string) - Slug of the post to display comments for

Features:

  • Fetches comments using SWR (stale-while-revalidate)
  • Real-time comment updates
  • Authentication check (shows login link if not authenticated)
  • User avatars and names

Usage:

import Comments from "@/components/comments/Comments";

<Comments postSlug="my-post-slug" />;

Reusability: Can be used on any page that needs a comment system. Just pass the appropriate identifier.


Navigation Components

Pagination (src/components/pagination/Pagination.jsx)

Purpose: Navigation component for paginated content.

Props:

  • page (number) - Current page number
  • hasPrev (boolean) - Whether previous page exists
  • hasNext (boolean) - Whether next page exists

Usage:

import Pagination from "@/components/pagination/Pagination";

<Pagination page={1} hasPrev={false} hasNext={true} />;

Reusability: Works with any paginated content. Adjust the URL pattern in the component for different routes.


Menu (src/components/Menu/Menu.jsx)

Purpose: Sidebar menu with popular posts and categories.

Usage:

import Menu from "@/components/Menu/Menu";

<Menu />;

Reusability: Customize by modifying the component to fetch different data sources.


Utility Components

AuthLinks (src/components/authLinks/AuthLinks.jsx)

Purpose: Displays login/logout button based on authentication status.

Usage:

import AuthLinks from "@/components/authLinks/AuthLinks";

<AuthLinks />;

Reusability: Can be placed anywhere authentication UI is needed.


ThemeToggle (src/components/themeToggle/ThemeToggle.jsx)

Purpose: Button to toggle between light and dark themes.

Usage:

import ThemeToggle from "@/components/themeToggle/ThemeToggle";

<ThemeToggle />;

Reusability: Can be placed anywhere theme switching is needed. Uses ThemeContext for state management.


πŸ”Œ API Endpoints

Authentication

GET/POST /api/auth/[...nextauth]

Purpose: NextAuth.js authentication handler.

Endpoints:

  • /api/auth/signin - Sign in page
  • /api/auth/signout - Sign out
  • /api/auth/callback/google - Google OAuth callback
  • /api/auth/callback/github - GitHub OAuth callback
  • /api/auth/session - Get current session

Usage: Handled automatically by NextAuth.js.


Posts

GET /api/posts

Purpose: Fetch paginated blog posts with optional category filter.

Query Parameters:

  • page (number) - Page number (default: 1)
  • cat (string, optional) - Category slug filter

Response:

{
  "posts": [
    {
      "id": "post-id",
      "title": "Post Title",
      "slug": "post-slug",
      "desc": "Post description",
      "img": "image-url",
      "views": 100,
      "catSlug": "style",
      "createdAt": "2024-01-01T00:00:00.000Z",
      "userEmail": "user@example.com"
    }
  ],
  "count": 50
}

Example:

const response = await fetch("/api/posts?page=1&cat=style");
const { posts, count } = await response.json();

POST /api/posts

Purpose: Create a new blog post.

Authentication: Required (user must be logged in)

Request Body:

{
  "title": "My New Post",
  "desc": "<p>Post content in HTML</p>",
  "img": "https://firebase-storage-url/image.jpg",
  "slug": "my-new-post",
  "catSlug": "style"
}

Response:

{
  "id": "new-post-id",
  "title": "My New Post",
  "slug": "my-new-post",
  ...
}

Example:

const response = await fetch("/api/posts", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    title: "My New Post",
    desc: "<p>Content</p>",
    img: "https://...",
    slug: "my-new-post",
    catSlug: "style",
  }),
});

GET /api/posts/[slug]

Purpose: Fetch a single blog post by slug and increment view count.

URL Parameter:

  • slug (string) - Post slug

Response:

{
  "id": "post-id",
  "title": "Post Title",
  "slug": "post-slug",
  "desc": "<p>Full post content</p>",
  "img": "image-url",
  "views": 101,
  "catSlug": "style",
  "createdAt": "2024-01-01T00:00:00.000Z",
  "user": {
    "name": "Author Name",
    "email": "author@example.com",
    "image": "avatar-url"
  }
}

Example:

const response = await fetch("/api/posts/my-post-slug");
const post = await response.json();

Categories

GET /api/categories

Purpose: Fetch all blog categories.

Response:

[
  {
    "id": "category-id",
    "slug": "style",
    "title": "Style",
    "img": "category-image-url"
  }
]

Example:

const response = await fetch("/api/categories");
const categories = await response.json();

Comments

GET /api/comments

Purpose: Fetch comments for a specific post.

Query Parameters:

  • postSlug (string) - Post slug to filter comments

Response:

[
  {
    "id": "comment-id",
    "desc": "Comment text",
    "createdAt": "2024-01-01T00:00:00.000Z",
    "user": {
      "name": "Commenter Name",
      "email": "commenter@example.com",
      "image": "avatar-url"
    },
    "postSlug": "post-slug"
  }
]

Example:

const response = await fetch("/api/comments?postSlug=my-post");
const comments = await response.json();

POST /api/comments

Purpose: Create a new comment on a blog post.

Authentication: Required (user must be logged in)

Request Body:

{
  "desc": "My comment text",
  "postSlug": "post-slug"
}

Response:

{
  "id": "new-comment-id",
  "desc": "My comment text",
  "postSlug": "post-slug",
  "userEmail": "user@example.com",
  "createdAt": "2024-01-01T00:00:00.000Z"
}

Example:

const response = await fetch("/api/comments", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    desc: "Great post!",
    postSlug: "my-post",
  }),
});

πŸ—Ί Routes & Pages

Homepage (/)

File: src/app/page.jsx

Purpose: Main landing page with featured post, categories, and recent posts.

Components Used:

  • Featured - Hero section
  • CategoryList - Category navigation
  • CardList - Recent posts
  • Menu - Sidebar

Query Parameters:

  • page (number) - Page number for pagination

Blog Page (/blog)

File: src/app/blog/page.jsx

Purpose: Category-filtered blog listing page.

Query Parameters:

  • page (number) - Page number
  • cat (string) - Category slug filter

Example URLs:

  • /blog - All posts
  • /blog?cat=style - Style category
  • /blog?cat=style&page=2 - Style category, page 2

Single Post Page (/posts/[slug])

File: src/app/posts/[slug]/page.jsx

Purpose: Display a single blog post with full content and comments.

Dynamic Route: [slug] - Post slug identifier

Features:

  • Full post content (HTML rendered)
  • Author information
  • View counter (incremented on page load)
  • Comments section
  • SEO metadata generation

Example URLs:

  • /posts/my-awesome-post
  • /posts/getting-started-with-nextjs

Write Page (/write)

File: src/app/write/page.jsx

Purpose: Create a new blog post (requires authentication).

Features:

  • Rich text editor (React Quill)
  • Image upload to Firebase Storage
  • Category selection
  • Title input
  • Auto-generated slug from title

Authentication: Redirects to homepage if not authenticated


Login Page (/login)

File: src/app/login/page.jsx

Purpose: User authentication page.

Features:

  • Google OAuth login
  • GitHub OAuth login (if configured)
  • Redirects to homepage after login

πŸ”‘ Key Functionalities

1. Authentication Flow

How it works:

  1. User clicks "Login" β†’ Redirected to NextAuth sign-in page
  2. User selects OAuth provider (Google/GitHub)
  3. OAuth callback β†’ NextAuth creates/updates user in database
  4. Session created β†’ User is authenticated
  5. Session stored in database via PrismaAdapter

Code Location:

  • Configuration: src/utils/auth.js
  • Handler: src/app/api/auth/[...nextauth]/route.js
  • Provider: src/providers/AuthProvider.jsx

2. Post Creation Flow

How it works:

  1. User navigates to /write (must be authenticated)
  2. User enters title, selects category, uploads image
  3. Image uploads to Firebase Storage β†’ Returns URL
  4. User writes content in rich text editor (React Quill)
  5. On "Publish" β†’ POST request to /api/posts
  6. API creates post in database with user email
  7. Redirects to new post page

Code Location:

  • Page: src/app/write/page.jsx
  • API: src/app/api/posts/route.js (POST handler)

3. Image Upload Flow

How it works:

  1. User selects image file in write page
  2. useEffect hook triggers on file selection
  3. Creates Firebase Storage reference
  4. Uploads file with uploadBytesResumable (resumable upload)
  5. Monitors upload progress
  6. On completion β†’ Gets download URL from Firebase
  7. URL stored in component state β†’ Used when creating post

Code Location:

  • src/app/write/page.jsx (lines 36-75)

4. Comment System

How it works:

  1. User views post β†’ Comments component fetches comments via SWR
  2. If authenticated β†’ Shows comment input form
  3. User submits comment β†’ POST to /api/comments
  4. Comment created with user email from session
  5. SWR mutate() refreshes comments list
  6. New comment appears immediately

Code Location:

  • Component: src/components/comments/Comments.jsx
  • API: src/app/api/comments/route.js

5. Theme Toggle

How it works:

  1. Theme state managed in ThemeContext
  2. Theme preference stored in localStorage
  3. ThemeProvider applies theme class to DOM
  4. CSS variables change based on theme class
  5. Toggle button updates context state

Code Location:

  • Context: src/context/ThemeContext.jsx
  • Provider: src/providers/ThemeProvider.jsx
  • Toggle: src/components/themeToggle/ThemeToggle.jsx

6. Pagination

How it works:

  1. API endpoint calculates skip/take based on page number
  2. Fetches posts and total count in transaction
  3. Frontend calculates hasPrev and hasNext flags
  4. Pagination component renders prev/next buttons
  5. Clicking buttons updates URL query parameter
  6. Page re-renders with new data

Code Location:

  • API: src/app/api/posts/route.js (GET handler)
  • Component: src/components/pagination/Pagination.jsx

7. View Counter

How it works:

  1. User visits post page β†’ GET /api/posts/[slug]
  2. API uses Prisma update with increment operation
  3. Atomically increments view count and fetches post
  4. View count displayed on post page

Code Location:

  • API: src/app/api/posts/[slug]/route.js

πŸ’» Code Examples

Server Component with Data Fetching

// src/app/blog/page.jsx
const BlogPage = async ({ searchParams }) => {
  const page = parseInt(searchParams.page) || 1;
  const { cat } = searchParams;

  return (
    <div>
      <CardList page={page} cat={cat} />
    </div>
  );
};

Key Points:

  • async component = Server Component
  • searchParams from Next.js App Router
  • No useEffect or useState needed

Client Component with State

// src/app/write/page.jsx
"use client";

const WritePage = () => {
  const [title, setTitle] = useState("");
  const [value, setValue] = useState("");

  const handleSubmit = async () => {
    await fetch("/api/posts", {
      method: "POST",
      body: JSON.stringify({ title, desc: value }),
    });
  };

  return (
    <div>
      <input onChange={(e) => setTitle(e.target.value)} />
      <ReactQuill value={value} onChange={setValue} />
      <button onClick={handleSubmit}>Publish</button>
    </div>
  );
};

Key Points:

  • "use client" directive required
  • Uses React hooks (useState)
  • Handles user interactions

API Route with Authentication

// src/app/api/posts/route.js
export const POST = async (req) => {
  const session = await getAuthSession();

  if (!session) {
    return new NextResponse(JSON.stringify({ message: "Not Authenticated!" }), {
      status: 401,
    });
  }

  const body = await req.json();
  const post = await prisma.post.create({
    data: { ...body, userEmail: session.user.email },
  });

  return new NextResponse(JSON.stringify(post), { status: 201 });
};

Key Points:

  • Server-side authentication check
  • Uses Prisma for database operations
  • Returns JSON response

Using SWR for Data Fetching

// src/components/comments/Comments.jsx
const Comments = ({ postSlug }) => {
  const { data, mutate, isLoading } = useSWR(
    `http://localhost:3000/api/comments?postSlug=${postSlug}`,
    fetcher
  );

  const handleSubmit = async () => {
    await fetch("/api/comments", {
      method: "POST",
      body: JSON.stringify({ desc, postSlug }),
    });
    mutate(); // Refresh data
  };

  return (
    <div>
      {isLoading ? "Loading..." : data?.map(comment => ...)}
    </div>
  );
};

Key Points:

  • SWR handles caching and revalidation
  • mutate() refreshes data after mutation
  • Automatic loading states

Prisma Query with Relations

// Fetch post with related user data
const post = await prisma.post.findUnique({
  where: { slug },
  include: { user: true }, // Include related User data
});

// Fetch comments with user data
const comments = await prisma.comment.findMany({
  where: { postSlug },
  include: { user: true },
});

Key Points:

  • include fetches related data
  • Type-safe queries
  • Automatic relationship resolution

πŸ”„ Reusing Components

Using Card Component in Your Project

  1. Copy the component:

    cp src/components/card/Card.jsx your-project/components/
    cp src/components/card/card.module.css your-project/components/
  2. Import and use:

    import Card from "@/components/card/Card";
    
    <Card item={postData} priority={true} />;
  3. Customize styling:

    • Modify card.module.css for your design
    • Adjust props if needed

Using Comments Component

  1. Copy files:

    cp src/components/comments/Comments.jsx your-project/
    cp src/components/comments/comments.module.css your-project/
  2. Install dependencies:

    npm install swr next-auth
  3. Set up API endpoint:

    • Create /api/comments route
    • Match the expected response format
  4. Use in your page:

    import Comments from "@/components/comments/Comments";
    
    <Comments postSlug="your-post-id" />;

Using Theme Toggle

  1. Copy theme context and provider:

    cp src/context/ThemeContext.jsx your-project/
    cp src/providers/ThemeProvider.jsx your-project/
    cp src/components/themeToggle/ThemeToggle.jsx your-project/
  2. Wrap your app:

    import { ThemeContextProvider } from "@/context/ThemeContext";
    import ThemeProvider from "@/providers/ThemeProvider";
    
    <ThemeContextProvider>
      <ThemeProvider>{children}</ThemeProvider>
    </ThemeContextProvider>;
  3. Add theme toggle button:

    import ThemeToggle from "@/components/themeToggle/ThemeToggle";
    
    <ThemeToggle />;
  4. Set up CSS variables:

    • Define light/dark theme variables in your CSS
    • Use [data-theme="dark"] selector

Using Pagination Component

  1. Copy component:

    cp src/components/pagination/Pagination.jsx your-project/
    cp src/components/pagination/pagination.module.css your-project/
  2. Use with your data:

    import Pagination from "@/components/pagination/Pagination";
    
    const hasPrev = page > 1;
    const hasNext = page * itemsPerPage < totalItems;
    
    <Pagination page={page} hasPrev={hasPrev} hasNext={hasNext} />;
  3. Customize URL pattern:

    • Modify the href in Pagination component to match your routes

🏷 Keywords

Technologies:

  • Next.js
  • React
  • MongoDB
  • Prisma
  • NextAuth.js
  • Firebase
  • OAuth
  • Server Components
  • App Router
  • TypeScript
  • SWR
  • React Quill
  • CSS Modules

Concepts:

  • Full-stack development
  • Server-side rendering
  • Authentication
  • Authorization
  • Database ORM
  • RESTful API
  • Pagination
  • Rich text editing
  • Image upload
  • Dark mode
  • SEO optimization
  • Responsive design

Use Cases:

  • Blogging platform
  • Content management
  • User authentication
  • Comment system
  • Category filtering
  • Post management

πŸ“ Conclusion

This Blog App is a comprehensive example of a modern full-stack Next.js application. It demonstrates:

  • βœ… Best Practices: Server Components, API Routes, Type-safe database queries
  • βœ… Authentication: OAuth integration with NextAuth.js
  • βœ… Database: MongoDB with Prisma ORM
  • βœ… File Storage: Firebase Storage integration
  • βœ… User Experience: Dark mode, responsive design, SEO optimization
  • βœ… Code Organization: Modular components, reusable utilities

Learning Outcomes:

By studying this project, you'll learn:

  1. How to structure a Next.js 14 App Router application
  2. Server vs Client Components and when to use each
  3. Authentication implementation with NextAuth.js
  4. Database operations with Prisma ORM
  5. API route creation and best practices
  6. Image upload and storage with Firebase
  7. Rich text editing with React Quill
  8. State management with React Context
  9. Data fetching patterns (SWR, Server Components)
  10. SEO optimization with dynamic metadata

Next Steps:

  • Customize the design and styling
  • Add more features (likes, bookmarks, search)
  • Implement admin dashboard
  • Add email notifications
  • Set up CI/CD pipeline
  • Deploy to production

Happy Coding! πŸŽ‰

Feel free to use this project repository and extend this project further!

If you have any questions or want to share your work, reach out via GitHub or my portfolio at https://arnob-mahmud.vercel.app/.

Enjoy building and learning! πŸš€

Thank you! 😊


About

A modern, full-featured blogging platform built with Next.js 14, featuring authentication, rich text editing, comments, categories, and dark mode support. This project demonstrates best practices in React, Next.js App Router, Prisma ORM, MongoDB, and NextAuth.js.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published