From 8056b67072dfc3ecb5f9eb33828bc4e325928fec Mon Sep 17 00:00:00 2001 From: Cypro Freelance <110410268+Proxyy587@users.noreply.github.com> Date: Thu, 25 Jul 2024 23:59:21 +0530 Subject: [PATCH] CRUD based pages multilogs --- app/(auth)/admin/changelogs/page.tsx | 199 +----------------- .../[slug]/page.tsx | 8 +- app/(auth)/admin/multi-logs/page.tsx | 133 ++++++++++++ app/(auth)/admin/page.tsx | 2 +- app/(root)/changelogs/[slug]/page.tsx | 50 ++++- app/api/mdx/pages/[slug]/route.ts | 64 ++---- app/api/mdx/pages/route.ts | 89 ++++---- lib/db.ts | 10 +- lib/models/multiLogs.ts | 0 9 files changed, 258 insertions(+), 297 deletions(-) rename app/(auth)/admin/{changelogs => multi-logs}/[slug]/page.tsx (92%) create mode 100644 app/(auth)/admin/multi-logs/page.tsx create mode 100644 lib/models/multiLogs.ts diff --git a/app/(auth)/admin/changelogs/page.tsx b/app/(auth)/admin/changelogs/page.tsx index 07637dc..02a5ba3 100644 --- a/app/(auth)/admin/changelogs/page.tsx +++ b/app/(auth)/admin/changelogs/page.tsx @@ -24,20 +24,7 @@ import { import { Input } from "@/components/ui/input"; import { logsSchema } from "@/lib/validations/validation"; import { z } from "zod"; -import { useRouter } from "next/navigation"; import { useToast } from "@/components/ui/use-toast"; -import dynamic from "next/dynamic"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogFooter, - DialogTitle, -} from "@/components/ui/dialog"; - -const MarkdownEditor = dynamic(() => import("@uiw/react-md-editor"), { - ssr: false, -}); interface LogEntry { _id: string; @@ -46,54 +33,13 @@ interface LogEntry { bullets: { point: string }[]; } -interface PageEntry { - title: string; - slug: string; - content: string; // Add content to the PageEntry interface -} - type LogsFormValues = z.infer; const AdminLogPage = () => { const [logs, setLogs] = useState([]); - const [pages, setPages] = useState([]); const [error, setError] = useState(""); const { toast } = useToast(); - const router = useRouter(); const [loading, setLoading] = useState(false); - const [open, setOpen] = useState(false); - const [pageTitle, setPageTitle] = useState(""); - const [selectedPage, setSelectedPage] = useState(null); - - useEffect(() => { - fetch("/api/mdx/pages") - .then((response) => response.json()) - .then((data) => setPages(data)) - .catch((error) => console.error("Failed to load pages", error)); - }, []); - - const createPage = async () => { - setLoading(true); - const slug = pageTitle.toLowerCase().replace(/\s+/g, "-"); - const response = await fetch("/api/mdx/pages", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ title: pageTitle, slug, content: "" }), - }); - - if (response.ok) { - const newPage = await response.json(); - setPages([...pages, newPage]); - setPageTitle(""); - setOpen(false); - setLoading(false); - } else { - console.error("Failed to create page"); - setLoading(false); - } - }; const form = useForm({ resolver: zodResolver(logsSchema), @@ -123,31 +69,6 @@ const AdminLogPage = () => { } }; - const fetchPages = async () => { - try { - const response = await fetch("/api/mdx/pages", { method: "GET" }); - if (response.ok) { - const data: PageEntry[] = await response.json(); - setPages(data); - } else { - throw new Error(`HTTP error! status: ${response.status}`); - } - } catch (error: any) { - setError(error.message || "Failed to fetch pages"); - } - }; - - useEffect(() => { - fetchLogs(); - fetchPages(); - const interval = setInterval(() => { - fetchLogs(); - fetchPages(); - }, 10000); - - return () => clearInterval(interval); - }, []); - const onSubmit: SubmitHandler = async (data) => { setLoading(true); const response = await fetch("/api/uploadlogs", { @@ -182,6 +103,15 @@ const AdminLogPage = () => { } }; + useEffect(() => { + fetchLogs(); + const interval = setInterval(() => { + fetchLogs(); + }, 10000); + + return () => clearInterval(interval); + }, []); + return (

Server Logs Form

@@ -258,71 +188,6 @@ const AdminLogPage = () => { -
- {/*

Changelog Management

*/} -
-

- Multi Log Page -

- - - - - Enter Page Title - - setPageTitle(e.target.value)} - placeholder="Page Title" - /> - - - - - -
-
-

Existing Pages

-

Total Pages: {pages.length}

- - - - Slug - Actions - - - - {pages.map((page) => ( - - - - {page.slug} - - - - - - - ))} - -
-
-
- {/* Section to list and delete logs */}

Existing Logs

@@ -360,52 +225,6 @@ const AdminLogPage = () => {
- - {/* Section to edit selected page */} - {selectedPage && ( -
-

Edit Page

- { - if (value !== undefined) { - setSelectedPage((prev) => ({ - ...prev!, - content: value, - })); - } - }} - /> - -
- )}
); }; diff --git a/app/(auth)/admin/changelogs/[slug]/page.tsx b/app/(auth)/admin/multi-logs/[slug]/page.tsx similarity index 92% rename from app/(auth)/admin/changelogs/[slug]/page.tsx rename to app/(auth)/admin/multi-logs/[slug]/page.tsx index d1a1501..cfba81c 100644 --- a/app/(auth)/admin/changelogs/[slug]/page.tsx +++ b/app/(auth)/admin/multi-logs/[slug]/page.tsx @@ -32,18 +32,16 @@ const EditPage = ({ params }: { params: { slug: string } }) => { const savePage = async () => { setLoading(true); - const response = await fetch(`/api/mdx/pages/${slug}`, { + const response = await fetch(`/api/mdx/pages/${slug}?slug=${slug}`, { method: "PUT", - headers: { - "Content-Type": "application/json", - }, + headers: { "Content-Type": "application/json" }, body: JSON.stringify({ title, content }), }); if (response.ok) { setLoading(false); toast({ description: "Page successfully updated" }); - router.push("/admin/changelogs"); + router.push("/admin/multi-logs"); } else { setLoading(false); toast({ description: "Page update failed", variant: "destructive" }); diff --git a/app/(auth)/admin/multi-logs/page.tsx b/app/(auth)/admin/multi-logs/page.tsx new file mode 100644 index 0000000..c168e1d --- /dev/null +++ b/app/(auth)/admin/multi-logs/page.tsx @@ -0,0 +1,133 @@ +"use client"; +import React, { useEffect, useState } from "react"; +import { Button } from "@/components/ui/button"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Input } from "@/components/ui/input"; +import { useRouter } from "next/navigation"; +import { useToast } from "@/components/ui/use-toast"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, +} from "@/components/ui/dialog"; + +interface PageEntry { + title: string; + slug: string; + content: string; +} + +const AdminLogPage = () => { + const [pages, setPages] = useState([]); + const { toast } = useToast(); + const router = useRouter(); + const [loading, setLoading] = useState(false); + const [open, setOpen] = useState(false); + const [pageTitle, setPageTitle] = useState(""); + + useEffect(() => { + fetch("/api/mdx/pages") + .then((response) => response.json()) + .then((data) => setPages(data)) + .catch((error) => console.error("Failed to load pages", error)); + }, []); + + const createPage = async () => { + setLoading(true); + const slug = pageTitle.toLowerCase().replace(/\s+/g, "-"); + const response = await fetch("/api/mdx/pages", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ title: pageTitle, slug, content: "" }), + }); + + if (response.ok) { + const newPage = await response.json(); + setPages([...pages, newPage]); + setPageTitle(""); + setOpen(false); + setLoading(false); + toast({ description: "Page created successfully" }); + } else { + console.error("Failed to create page"); + toast({ description: "Some Error Occured" }); + setLoading(false); + } + }; + + return ( +
+
+

Create New Page

+ + + + + Enter Page Title + + setPageTitle(e.target.value)} + placeholder="Page Title" + /> + + + + + +
+
+

Existing Pages

+

Total Pages: {pages.length}

+ + + + Slug + Actions + + + + {pages.map((page) => ( + + + + {page.slug} + + + + + + + ))} + +
+
+
+ ); +}; + +export default AdminLogPage; diff --git a/app/(auth)/admin/page.tsx b/app/(auth)/admin/page.tsx index 8f2d3fa..7085ad9 100644 --- a/app/(auth)/admin/page.tsx +++ b/app/(auth)/admin/page.tsx @@ -11,7 +11,7 @@ const AdminPage = () => { - + diff --git a/app/(root)/changelogs/[slug]/page.tsx b/app/(root)/changelogs/[slug]/page.tsx index 4604476..2ae361a 100644 --- a/app/(root)/changelogs/[slug]/page.tsx +++ b/app/(root)/changelogs/[slug]/page.tsx @@ -8,15 +8,41 @@ const Page = ({ params }: { params: { slug: string } }) => { const [page, setPage] = useState<{ title: string; content: string } | null>( null ); + const [loading, setLoading] = useState(true); + const [notFound, setNotFound] = useState(false); useEffect(() => { - fetch(`/api/mdx/pages/${slug}`) - .then((response) => response.json()) - .then((data) => setPage(data)) - .catch((error) => console.error("Failed to load page", error)); + const fetchPage = async () => { + try { + const response = await fetch(`/api/mdx/pages/${slug}`); + if (response.ok) { + const data = await response.json(); + setPage(data); + } else { + if (response.status === 404) { + setNotFound(true); + } + } + } catch (error) { + console.error("Failed to load page", error); + setNotFound(true); + } finally { + setLoading(false); + } + }; + + fetchPage(); }, [slug]); - if (!page) { + if (loading) { + return ( +
+

Loading...

+
+ ); + } + + if (notFound) { return (

@@ -29,10 +55,18 @@ const Page = ({ params }: { params: { slug: string } }) => { ); } + if (!page) { + return null; + } + return ( -
-

{page.title}

- {page.content} +
+

+ {page.title} +

+ + {page.content} +
); }; diff --git a/app/api/mdx/pages/[slug]/route.ts b/app/api/mdx/pages/[slug]/route.ts index 9917b3b..95e31a3 100644 --- a/app/api/mdx/pages/[slug]/route.ts +++ b/app/api/mdx/pages/[slug]/route.ts @@ -1,54 +1,22 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import { NextRequest, NextResponse } from "next/server"; import clientPromise from "@/lib/db"; -export async function GET(req: NextApiRequest, res: NextApiResponse) { - const { slug } = req.query; - try { - const client = await clientPromise; - const db = client.db(); - const page = await db.collection("pages").findOne({ slug }); - if (page) { - res.status(200).json(page); - } else { - res.status(404).json({ error: "Page not found" }); - } - } catch (error) { - res.status(500).json({ error: "Failed to load page" }); - } -} +export const GET = async ( + req: NextRequest, + { params }: { params: { slug: string } } +) => { + const client = await clientPromise; + const db = client.db(); + const { slug } = params; -export async function PUT(req: NextApiRequest, res: NextApiResponse) { - const { slug } = req.query; - const { title, content } = req.body; - try { - const client = await clientPromise; - const db = client.db(); - const result = await db - .collection("pages") - .updateOne({ slug }, { $set: { title, content } }); - if (result.matchedCount > 0) { - const updatedPage = await db.collection("pages").findOne({ slug }); - res.status(200).json(updatedPage); - } else { - res.status(404).json({ error: "Page not found" }); - } - } catch (error) { - res.status(500).json({ error: "Failed to update page" }); + if (!slug) { + return NextResponse.json({ message: "Slug is required" }, { status: 400 }); } -} -export async function DELETE(req: NextApiRequest, res: NextApiResponse) { - const { slug } = req.query; - try { - const client = await clientPromise; - const db = client.db(); - const result = await db.collection("pages").deleteOne({ slug }); - if (result.deletedCount > 0) { - res.status(200).json({ message: "Page successfully deleted" }); - } else { - res.status(404).json({ error: "Page not found" }); - } - } catch (error) { - res.status(500).json({ error: "Failed to delete page" }); + const page = await db.collection("pages").findOne({ slug }); + if (page) { + return NextResponse.json(page, { status: 200 }); + } else { + return NextResponse.json({ message: "Page not found" }, { status: 404 }); } -} +}; diff --git a/app/api/mdx/pages/route.ts b/app/api/mdx/pages/route.ts index c8b101a..a0e245d 100644 --- a/app/api/mdx/pages/route.ts +++ b/app/api/mdx/pages/route.ts @@ -1,46 +1,55 @@ -import { NextResponse } from "next/server"; +import { NextRequest, NextResponse } from "next/server"; import clientPromise from "@/lib/db"; -export async function GET() { - try { - const client = await clientPromise; - const db = client.db(); - const pages = await db.collection("pages").find({}).toArray(); - return NextResponse.json(pages, { status: 200 }); - } catch (error) { +export const GET = async () => { + const client = await clientPromise; + const db = client.db(); + const pages = await db.collection("pages").find().toArray(); + return NextResponse.json(pages, { status: 200 }); +}; + +export const PUT = async ( + req: NextRequest, + { params }: { params: { slug: string } } +) => { + const client = await clientPromise; + const db = client.db(); + const { slug } = params; + const { title, content } = await req.json(); + + if (!slug) { + return NextResponse.json({ message: "Slug is required" }, { status: 400 }); + } + + const result = await db + .collection("pages") + .findOneAndUpdate( + { slug }, + { $set: { title, content } }, + { returnDocument: "after" } + ); + + if (result && result.value) { + const page = result.value; + return NextResponse.json(page, { status: 200 }); + } else { + return NextResponse.json({ message: "Page not found" }, { status: 404 }); + } +}; + +export const POST = async (req: NextRequest) => { + const client = await clientPromise; + const db = client.db(); + const { title, slug, content } = await req.json(); + + if (!title || !slug || !content) { return NextResponse.json( - { error: "Failed to load pages" }, - { status: 500 } + { message: "Missing required fields" }, + { status: 400 } ); } -} -export async function POST(req: Request) { - try { - const body = await req.json(); - const { title, slug, content } = body; - - const client = await clientPromise; - const db = client.db(); - const result = await db - .collection("pages") - .insertOne({ title, slug, content }); - - if (result.acknowledged) { - const newPage = await db - .collection("pages") - .findOne({ _id: result.insertedId }); - return NextResponse.json(newPage, { status: 201 }); - } else { - return NextResponse.json( - { error: "Failed to create page" }, - { status: 500 } - ); - } - } catch (error) { - return NextResponse.json( - { error: "Failed to create page" }, - { status: 500 } - ); - } -} + const newPage = { title, slug, content }; + const result = await db.collection("pages").insertOne(newPage); + return NextResponse.json(newPage, { status: 201 }); +}; diff --git a/lib/db.ts b/lib/db.ts index a21e1a0..3cc3e8e 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -2,21 +2,21 @@ import { MongoClient } from "mongodb"; // Ensure the environment variable is set if (!process.env.MONGODB_URI) { - throw new Error('Invalid/Missing environment variable: "MONGODB_URI"'); + throw new Error('Invalid/Missing environment variable: "MONGODB_URI"'); } const uri = process.env.MONGODB_URI; const options = { - // Add any SSL/TLS options if needed, for example: - // ssl: true, - // tlsAllowInvalidCertificates: true, + // Add any SSL/TLS options if needed, for example: + // ssl: true, + // tlsAllowInvalidCertificates: true, }; let client: MongoClient; let clientPromise: Promise; declare global { - var _mongoClientPromise: Promise | undefined; + var _mongoClientPromise: Promise | undefined; } client = new MongoClient(uri, options); diff --git a/lib/models/multiLogs.ts b/lib/models/multiLogs.ts new file mode 100644 index 0000000..e69de29