-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
895 additions
and
863 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,50 @@ | ||
## Blog Website - Shiva Yadav | ||
|
||
**Techstack used:** | ||
- Nextjs | ||
- Tailwind CSS | ||
- Shadcn UI | ||
- MDX | ||
- Next Auth | ||
- Prisma ORM | ||
- MongoDB | ||
# Modern Blog Platform | ||
|
||
A full-stack blog platform built with Next.js 14, featuring server components, server actions, and modern authentication. | ||
|
||
## 🚀 Features | ||
|
||
- **Authentication & Authorization** | ||
- Next-Auth integration with Google provider | ||
- Protected admin routes | ||
- Role-based access control | ||
|
||
- **Blog Management** | ||
- Create, edit, and delete blog posts | ||
- Rich text editor with TipTap | ||
- Image upload with Cloudinary | ||
- SEO-friendly URLs with slugs | ||
|
||
- **User Interactions** | ||
- Like/Unlike posts | ||
- Comment system | ||
- Real-time updates | ||
- Responsive design | ||
|
||
- **Admin Dashboard** | ||
- Post management interface | ||
- Post analytics (likes, comments) | ||
- User-friendly CRUD operations | ||
|
||
## 🛠️ Tech Stack | ||
|
||
- **Frontend** | ||
- Next.js 14 (React) | ||
- TypeScript | ||
- Tailwind CSS | ||
- Shadcn UI Components | ||
- TipTap Editor | ||
|
||
- **Backend** | ||
- Next.js Server Components | ||
- Server Actions | ||
- Prisma ORM | ||
- PostgreSQL | ||
|
||
- **Authentication** | ||
- NextAuth.js v5 | ||
- Google OAuth | ||
|
||
- **Storage** | ||
- Cloudinary (Images) | ||
- PostgreSQL (Data) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,91 +1,91 @@ | ||
"use server"; | ||
|
||
import { auth } from "@/auth"; | ||
import { revalidatePath } from "next/cache"; | ||
import Prisma from "../../prisma"; | ||
import { redirect } from "next/navigation"; | ||
import { z } from "zod"; | ||
|
||
const CommentSchema = z.object({ | ||
content: z.string().min(1, { message: "Comment cannot be empty" }), | ||
postId: z.string(), | ||
}); | ||
|
||
export async function addComment(formData: FormData) { | ||
const session = await auth(); | ||
if (!session?.user) { | ||
redirect("/login"); | ||
} | ||
|
||
const validation = CommentSchema.safeParse({ | ||
content: formData.get("content"), | ||
postId: formData.get("postId"), | ||
}); | ||
|
||
if (!validation.success) { | ||
return { | ||
error: "Invalid comment data", | ||
}; | ||
} | ||
|
||
const { content, postId } = validation.data; | ||
|
||
const user = await Prisma.user.findUnique({ | ||
where: { email: session.user.email! }, | ||
}); | ||
|
||
if (!user) { | ||
return { | ||
error: "User not found", | ||
}; | ||
} | ||
|
||
await Prisma.comment.create({ | ||
data: { | ||
content, | ||
postId, | ||
userId: user.id, | ||
}, | ||
}); | ||
|
||
revalidatePath("/post/[slug]", "page"); | ||
} | ||
|
||
export async function toggleLike(postId: string): Promise<void> { | ||
const session = await auth(); | ||
if (!session?.user) { | ||
redirect("/login"); | ||
} | ||
|
||
const user = await Prisma.user.findUnique({ | ||
where: { email: session.user.email! }, | ||
}); | ||
|
||
if (!user) { | ||
throw new Error("User not found"); | ||
} | ||
|
||
const existingLike = await Prisma.like.findFirst({ | ||
where: { | ||
postId, | ||
userId: user.id, | ||
}, | ||
}); | ||
|
||
if (existingLike) { | ||
await Prisma.like.delete({ | ||
where: { | ||
id: existingLike.id, | ||
}, | ||
}); | ||
} else { | ||
await Prisma.like.create({ | ||
data: { | ||
postId, | ||
userId: user.id, | ||
}, | ||
}); | ||
} | ||
|
||
revalidatePath("/post/[slug]", "page"); | ||
"use server"; | ||
|
||
import { auth } from "@/auth"; | ||
import { revalidatePath } from "next/cache"; | ||
import Prisma from "../../prisma"; | ||
import { redirect } from "next/navigation"; | ||
import { z } from "zod"; | ||
|
||
const CommentSchema = z.object({ | ||
content: z.string().min(1, { message: "Comment cannot be empty" }), | ||
postId: z.string(), | ||
}); | ||
|
||
export async function addComment(formData: FormData) { | ||
const session = await auth(); | ||
if (!session?.user) { | ||
redirect("/login"); | ||
} | ||
|
||
const validation = CommentSchema.safeParse({ | ||
content: formData.get("content"), | ||
postId: formData.get("postId"), | ||
}); | ||
|
||
if (!validation.success) { | ||
return { | ||
error: "Invalid comment data", | ||
}; | ||
} | ||
|
||
const { content, postId } = validation.data; | ||
|
||
const user = await Prisma.user.findUnique({ | ||
where: { email: session.user.email! }, | ||
}); | ||
|
||
if (!user) { | ||
return { | ||
error: "User not found", | ||
}; | ||
} | ||
|
||
await Prisma.comment.create({ | ||
data: { | ||
content, | ||
postId, | ||
userId: user.id, | ||
}, | ||
}); | ||
|
||
revalidatePath("/post/[slug]", "page"); | ||
} | ||
|
||
export async function toggleLike(postId: string): Promise<void> { | ||
const session = await auth(); | ||
if (!session?.user) { | ||
redirect("/login"); | ||
} | ||
|
||
const user = await Prisma.user.findUnique({ | ||
where: { email: session.user.email! }, | ||
}); | ||
|
||
if (!user) { | ||
throw new Error("User not found"); | ||
} | ||
|
||
const existingLike = await Prisma.like.findFirst({ | ||
where: { | ||
postId, | ||
userId: user.id, | ||
}, | ||
}); | ||
|
||
if (existingLike) { | ||
await Prisma.like.delete({ | ||
where: { | ||
id: existingLike.id, | ||
}, | ||
}); | ||
} else { | ||
await Prisma.like.create({ | ||
data: { | ||
postId, | ||
userId: user.id, | ||
}, | ||
}); | ||
} | ||
|
||
revalidatePath("/post/[slug]", "page"); | ||
} |
Oops, something went wrong.