From db688838248991023f8a9918a9dfd3dcaebe5fa3 Mon Sep 17 00:00:00 2001 From: martinvibes Date: Tue, 29 Jul 2025 00:25:41 +0100 Subject: [PATCH 1/3] feat: implement admin content management --- package.json | 2 + .../admin/content-management/page.tsx | 1132 ++++++++++++++++- src/components/ui/card.tsx | 22 +- src/components/ui/dropdown-menu.tsx | 257 ++++ src/components/ui/progress.tsx | 31 + 5 files changed, 1424 insertions(+), 20 deletions(-) create mode 100644 src/components/ui/dropdown-menu.tsx create mode 100644 src/components/ui/progress.tsx diff --git a/package.json b/package.json index c2b91ef..22a1b65 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-checkbox": "^1.2.3", "@radix-ui/react-dialog": "^1.1.14", + "@radix-ui/react-dropdown-menu": "^2.1.15", + "@radix-ui/react-progress": "^1.1.7", "@radix-ui/react-select": "^2.2.5", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", diff --git a/src/app/dashboard/admin/content-management/page.tsx b/src/app/dashboard/admin/content-management/page.tsx index fb7108d..89da754 100644 --- a/src/app/dashboard/admin/content-management/page.tsx +++ b/src/app/dashboard/admin/content-management/page.tsx @@ -1,19 +1,1133 @@ -"use-client"; +"use client"; + +import { useState } from "react"; import { Header } from "@/components/dashboard/header"; +import { + ArrowLeft, + Star, + Eye, + Search, + Filter, + ChevronDown, +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Input } from "@/components/ui/input"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Card, CardContent } from "@/components/ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { Progress } from "@/components/ui/progress"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; -export default function ContentManagement() { +type ViewType = "dashboard" | "book-details" | "book-approval"; +type TabType = "all-books" | "pending-approval" | "reported-content"; - return ( - <> +interface Book { + id: string; + title: string; + author: string; + cover: string; + type: "Regular" | "NFT Edition"; + status: + | "Approved" + | "Pending" + | "Rejected" + | "Unresolved" + | "Resolved" + | "Valid"; + dateSubmitted: string; + datePublished?: string; + interactions?: string; + tokenId?: string; + walletAddress?: string; + mintingDate?: string; + reportType?: string; + reportedBy?: string; + rating?: number; + price?: string; + sold?: number; + isbn?: string; + language?: string; + pageCount?: string; + genre?: string[]; +} + +const mockBooks: Book[] = [ + { + id: "1", + title: "Native Invisibility", + author: "Darrin Collins", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Pending", + dateSubmitted: "17 May, 2025", + rating: 4.5, + price: "193 STRK", + sold: 57, + isbn: "978-3-16-148410-0", + language: "English", + pageCount: "21 Pages", + genre: ["Fiction", "Comic"], + }, + { + id: "2", + title: "The Silent Storm", + author: "Jane Mark", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Pending", + dateSubmitted: "12 May, 2025", + }, + { + id: "3", + title: "The Silent Storm", + author: "Jane Mark", + cover: "/placeholder.svg?height=120&width=80", + type: "NFT Edition", + status: "Pending", + dateSubmitted: "12 May, 2025", + mintingDate: "12 May, 2025", + }, + { + id: "4", + title: "The Silent Storm", + author: "Jane Mark", + cover: "/placeholder.svg?height=120&width=80", + type: "NFT Edition", + status: "Pending", + dateSubmitted: "12 May, 2025", + mintingDate: "12 May, 2025", + }, + { + id: "5", + title: "The Silent Storm", + author: "Jane Mark", + cover: "/placeholder.svg?height=120&width=80", + type: "NFT Edition", + status: "Pending", + dateSubmitted: "12 May, 2025", + mintingDate: "12 May, 2025", + }, + { + id: "6", + title: "Strange Waters", + author: "Olamide Musa", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Unresolved", + dateSubmitted: "4 June, 2025", + reportType: "Plagiarism", + reportedBy: "0x12...ong", + }, + { + id: "16", + title: "Strange Waters", + author: "Olamide Musa", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Resolved", + dateSubmitted: "4 June, 2025", + reportType: "Inappropriate", + reportedBy: "0x12...ong", + }, + { + id: "26", + title: "Strange Waters", + author: "Olamide Musa", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Resolved", + dateSubmitted: "4 June, 2025", + reportType: "Inappropriate", + reportedBy: "0x12...ong", + }, + { + id: "006", + title: "Strange Waters", + author: "Olamide Musa", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Unresolved", + dateSubmitted: "4 June, 2025", + reportType: "Plagiarism", + reportedBy: "0x12...ong", + }, + { + id: "216", + title: "Strange Waters", + author: "Olamide Musa", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Resolved", + dateSubmitted: "4 June, 2025", + reportType: "Inappropriate", + reportedBy: "0x12...ong", + }, + { + id: "601", + title: "Strange Waters", + author: "Olamide Musa", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Unresolved", + dateSubmitted: "4 June, 2025", + reportType: "Plagiarism", + reportedBy: "0x12...ong", + }, + { + id: "7", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, + { + id: "8", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, + { + id: "9", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, + { + id: "10", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, + { + id: "11", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, + { + id: "12", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, + { + id: "13", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, + { + id: "14", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, + { + id: "15", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, + { + id: "16", + title: "Whispers of Dawn", + author: "John Doe", + cover: "/placeholder.svg?height=120&width=80", + type: "Regular", + status: "Approved", + dateSubmitted: "12 September, 2025", + datePublished: "12 May, 2025", + interactions: "2.7k Read", + }, +]; + +const stats = { + totalBooks: 107, + approved: 69, + pendingApproval: 27, + rejected: 4, + reported: 107, + unpublished: 27, + nftEditionValidated: 4, + approvedStats: 8, +}; + +export default function ChainLibContentManagement() { + const [currentView, setCurrentView] = useState("dashboard"); + const [activeTab, setActiveTab] = useState("pending-approval"); + const [selectedBook, setSelectedBook] = useState(null); + const [timeFilter, setTimeFilter] = useState("This Week"); + + const handleBookClick = (book: Book) => { + setSelectedBook(book); + if (book.status === "Pending") { + setCurrentView("book-approval"); + } else { + setCurrentView("book-details"); + } + }; + + const handleBackToDashboard = () => { + setCurrentView("dashboard"); + setSelectedBook(null); + }; + + const handleApprove = () => { + if (selectedBook) { + // Handle approval logic + console.log("Approved:", selectedBook.title); + handleBackToDashboard(); + } + }; + + const handleReject = () => { + if (selectedBook) { + // Handle rejection logic + console.log("Rejected:", selectedBook.title); + handleBackToDashboard(); + } + }; + + const renderDashboard = () => ( +
+ +
+ {/* Time Filter */} +
+
+ {["This Week", "This Month", "This Year", "All Time"].map( + (filter) => ( + + ) + )} +
+ +
+ + to + + +
+
+ + {/* Stats Grid */} +
+ + +
Total Books
+
+ {stats.totalBooks} +
+
+
+ + +
Approved
+
+ {stats.approved} +
+
+
+ + +
+ Pending Approval +
+
+ {stats.pendingApproval} +
+
+
+ + +
Rejected
+
+ {stats.rejected} +
+
+
+ + +
Reported
+
+ {stats.reported} +
+
+
+ + +
Unpublished
+
+ {stats.unpublished} +
+
+
+ + +
+ NFT Edition Validated +
+
+ {stats.nftEditionValidated} +
+
+
+ + +
Approved
+
+ {stats.approvedStats} +
+
+
+
+
+ + {/* Tabs */} + setActiveTab(value as TabType)} + className="bg-white rounded-lg border border-[#E7E7E7] p-4" + > +
+ + + All Books + + + Pending Approval + + 27 + + + + Reported Content + + + +
+
+ + +
+ + + + + + e.preventDefault()}> + Date Submitted + + e.preventDefault()}> + Title + + e.preventDefault()}> + Author + + + + + + + + + e.preventDefault()} + > + Regular + + e.preventDefault()} + > + NFT Edition + + + +
+
+ + + {renderBookTable( + mockBooks.filter((book) => book.status === "Approved"), + "all-books" + )} + + + + {renderBookTable( + mockBooks.filter((book) => book.status === "Pending"), + "pending-approval" + )} + + + + {renderBookTable( + mockBooks.filter( + (book) => + book.status === "Unresolved" || book.status === "Resolved" + ), + "reported-content" + )} + + +
+ Showing 1 to 10 of 107 + +
+
+
+ ); + + const renderBookTable = (books: Book[], tabType: string) => { + const getTableHeaders = () => { + switch (tabType) { + case "all-books": + return [ + "Cover", + "Title and Author", + "Status", + "Type", + "Date Published", + "Interactions", + "", + ]; + case "pending-approval": + if (books.some((book) => book.tokenId)) { + return [ + "Cover", + "Title and Author", + "Type", + "Date Submitted", + "Review Status", + "", + ]; + } + return [ + "Cover", + "Title and Author", + "Type", + "Date Submitted", + "Review Status", + "", + ]; + case "reported-content": + return [ + "Cover", + "Title and Author", + "Report Type", + "Reported By", + "Date", + "Status", + "", + ]; + default: + return []; + } + }; + + return ( +
+
+ + + + {getTableHeaders().map((header, index) => ( + + ))} + + + + {books.map((book) => ( + + + + {tabType === "all-books" && ( + <> + + + + + + )} + {tabType === "pending-approval" && ( + <> + {book.tokenId ? ( + <> + + + + + + ) : ( + <> + + + + + )} + + )} + {tabType === "reported-content" && ( + <> + + + + + + )} + + + ))} + +
+ {header} +
+ {"Book + +
+ {book.title} +
+
+ by {book.author} +
+
+ + {book.status} + + {book.type} + {book.datePublished} + +
+ + {book.interactions} +
+
+ {book.tokenId} + + {book.mintingDate} + + {book.walletAddress} + + + {book.status} + + + {book.type} + + {book.dateSubmitted} + + + {book.status} + + + {book.reportType} + + {book.reportedBy} + + {book.dateSubmitted} + + + {book.status} + + + +
+
+
+ ); + }; + + const renderBookDetails = () => { + if (!selectedBook) return null; + + return (
-
-

Content management

-

- Welcome to the Content Management section of the admin dashboard! Here, you can manage all aspects of content on your platform, including articles, blogs, and other media. This space is designed to help you maintain a rich and engaging content library for your users. + {/* Header */} +

+
+ +
+
+ + + AL + +
+
Anna Loop
+
anna***p@gmail.com
+
+
+
+ + {/* Book Info */} +
+
+ {selectedBook.title} +
+
+
+

+ {selectedBook.title} +

+

By {selectedBook.author}

+ {selectedBook.rating && ( +
+
+ + + {selectedBook.rating} + +
+
+ )} +
+ + {currentView === "book-approval" && ( +
+ + +
+ )} + + +
+
+ + {/* Book Details Grid */} +
+
+
Payment Type
+
One-Time Payment
+
+
+
Price
+
{selectedBook.price || "N/A"}
+
+
+
Published Date
+
{selectedBook.dateSubmitted}
+
+
+
Sold
+
{selectedBook.sold || "N/A"}
+
+
+ + {/* Description */} +
+

Description

+

+ Delves into the complex and often insidious ways in which indigenous + peoples and their unique experiences are rendered unseen and unheard + in the modern era.

+ +
+ + {/* Additional Info */} +
+
+
Genre(s)
+
+ {selectedBook.genre?.map((g) => ( + + {g} + + ))} +
+
+
+
Page count
+
{selectedBook.pageCount}
+
+
+
Language
+
{selectedBook.language}
+
+
+
ISBN
+
{selectedBook.isbn}
+
+ + {/* Performance Stats */} +
+

Book Performance Stats

+
+ + + + +
+ +
+ + +
Read
+
192
+
-10%
+
+
+ + +
+ Read Completion Rate +
+
75%
+
+5%
+
+
+ + +
Purchase
+
62
+
+8%
+
+
+ + +
Total Complete Read
+
70%
+
+
+ + +
Total Earning
+
$ 370.00
+
+
+ + +
Average Rating
+
+ + 3.5 +
+
+
+
+
+ + {/* Reviews Section */} +
+

Reviews and Rating

+ +
+
+
3.5
+
+ {[1, 2, 3, 4, 5].map((star) => ( + + ))} +
+
1202 Reviews
+
+ +
+ {[5, 4, 3, 2, 1].map((rating) => ( +
+ {rating} + +
+ ))} +
+
+ + {/* Individual Reviews */} +
+ {[1, 2, 3, 4, 5, 6].map((review) => ( +
+
+ + + AS + +
+
+ Adeja Samad +
+ {[1, 2, 3, 4].map((star) => ( + + ))} + +
+ Yesterday +
+

+ This was a great read, and I was hooked. However, the + death of my favorite character impacted my overall + enjoyment, which is why I'm rating it 4 stars instead of + 5. +

+
+ +
+ + + AR + + + Author Replied + • 1 Reply +
+
+
+
+
+ ))} +
+
+ + {/* Reports Section (if applicable) */} + {currentView === "book-details" && + selectedBook.status !== "Approved" && ( +
+

Reports & Comments

+ +
+
+
+ + + LV + +
+
+ Lana Victor + Yesterday +
+
+ + Plagiarism and Inappropriate Content + +
+

+ Presenting someone else's work and used images, that are + unsuitable, offensive, harmful, disturbing, often based + on societal norms, legal standards, age +

+
+
+
+ +
+
+ + + SY + +
+
+ Samuel Yaro + + 5 June, 2025 + +
+
+ + Inappropriate Content + +
+

+ Unsuitable, offensive, harmful, disturbing, often based + on societal norms, legal standards, age +

+
+
+
+
+
+ )} +
+ ); + }; + + return ( +
+
+ {currentView === "dashboard" && renderDashboard()} + {(currentView === "book-details" || currentView === "book-approval") && + renderBookDetails()}
- +
); } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx index d05bbc6..049c74e 100644 --- a/src/components/ui/card.tsx +++ b/src/components/ui/card.tsx @@ -1,18 +1,18 @@ -import * as React from "react" +import * as React from "react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function Card({ className, ...props }: React.ComponentProps<"div">) { return (
- ) + ); } function CardHeader({ className, ...props }: React.ComponentProps<"div">) { @@ -25,7 +25,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) { )} {...props} /> - ) + ); } function CardTitle({ className, ...props }: React.ComponentProps<"div">) { @@ -35,7 +35,7 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) { className={cn("leading-none font-semibold", className)} {...props} /> - ) + ); } function CardDescription({ className, ...props }: React.ComponentProps<"div">) { @@ -45,7 +45,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) { className={cn("text-muted-foreground text-sm", className)} {...props} /> - ) + ); } function CardAction({ className, ...props }: React.ComponentProps<"div">) { @@ -58,7 +58,7 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) { )} {...props} /> - ) + ); } function CardContent({ className, ...props }: React.ComponentProps<"div">) { @@ -68,7 +68,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) { className={cn("px-6", className)} {...props} /> - ) + ); } function CardFooter({ className, ...props }: React.ComponentProps<"div">) { @@ -78,7 +78,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) { className={cn("flex items-center px-6 [.border-t]:pt-6", className)} {...props} /> - ) + ); } export { @@ -89,4 +89,4 @@ export { CardAction, CardDescription, CardContent, -} +}; diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..ec51e9c --- /dev/null +++ b/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,257 @@ +"use client" + +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function DropdownMenu({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function DropdownMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean + variant?: "default" | "destructive" +}) { + return ( + + ) +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + ) +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ) +} + +function DropdownMenuSub({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + {children} + + + ) +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +} diff --git a/src/components/ui/progress.tsx b/src/components/ui/progress.tsx new file mode 100644 index 0000000..e7a416c --- /dev/null +++ b/src/components/ui/progress.tsx @@ -0,0 +1,31 @@ +"use client" + +import * as React from "react" +import * as ProgressPrimitive from "@radix-ui/react-progress" + +import { cn } from "@/lib/utils" + +function Progress({ + className, + value, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +export { Progress } From 09cc7fa731c92d29a0f3a20545b3594afe92d24f Mon Sep 17 00:00:00 2001 From: martinvibes Date: Tue, 29 Jul 2025 17:39:01 +0100 Subject: [PATCH 2/3] feat: add Chat SVG and enhance content management features --- public/Chat.svg | 3 + .../admin/content-management/page.tsx | 1720 ++++++++++++----- src/components/dashboard/header.tsx | 96 +- src/components/ui/textarea.tsx | 24 + 4 files changed, 1281 insertions(+), 562 deletions(-) create mode 100644 public/Chat.svg create mode 100644 src/components/ui/textarea.tsx diff --git a/public/Chat.svg b/public/Chat.svg new file mode 100644 index 0000000..9fa1d2b --- /dev/null +++ b/public/Chat.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/dashboard/admin/content-management/page.tsx b/src/app/dashboard/admin/content-management/page.tsx index 89da754..3a73cf7 100644 --- a/src/app/dashboard/admin/content-management/page.tsx +++ b/src/app/dashboard/admin/content-management/page.tsx @@ -9,6 +9,13 @@ import { Search, Filter, ChevronDown, + CheckCircle, + Edit, + MessageCircle, + MessageCircleCodeIcon, + DownloadCloud, + Download, + X, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; @@ -24,7 +31,18 @@ import { DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; -type ViewType = "dashboard" | "book-details" | "book-approval"; +import Image from "next/image"; +import check from "../../../../../public/Cover.png"; +import message from "../../../../../public/Chat.svg"; +import starknet from "../../../../../public/starknet.png"; +import you from "../../../../../public/you.svg"; +import user1 from "../../../../../public/user1.svg"; + +type ViewType = + | "dashboard" + | "book-details" + | "book-approval" + | "reported-content"; type TabType = "all-books" | "pending-approval" | "reported-content"; interface Book { @@ -39,7 +57,8 @@ interface Book { | "Rejected" | "Unresolved" | "Resolved" - | "Valid"; + | "Valid" + | "Reported"; dateSubmitted: string; datePublished?: string; interactions?: string; @@ -307,11 +326,15 @@ export default function ChainLibContentManagement() { const [activeTab, setActiveTab] = useState("pending-approval"); const [selectedBook, setSelectedBook] = useState(null); const [timeFilter, setTimeFilter] = useState("This Week"); + const [isRejectModalOpen, setIsRejectModalOpen] = useState(false); + const [rejectReason, setRejectReason] = useState(""); const handleBookClick = (book: Book) => { setSelectedBook(book); if (book.status === "Pending") { setCurrentView("book-approval"); + } else if (book.status === "Unresolved" || book.status === "Resolved") { + setCurrentView("reported-content"); } else { setCurrentView("book-details"); } @@ -331,253 +354,275 @@ export default function ChainLibContentManagement() { }; const handleReject = () => { - if (selectedBook) { + setIsRejectModalOpen(true); + }; + + const handleRejectSubmit = () => { + if (selectedBook && rejectReason.trim()) { // Handle rejection logic - console.log("Rejected:", selectedBook.title); + console.log("Rejected:", selectedBook.title, "Reason:", rejectReason); + setRejectReason(""); + setIsRejectModalOpen(false); handleBackToDashboard(); } }; + const handleRejectCancel = () => { + setRejectReason(""); + setIsRejectModalOpen(false); + }; + const renderDashboard = () => ( -
+
-
- {/* Time Filter */} -
-
- {["This Week", "This Month", "This Year", "All Time"].map( - (filter) => ( - - ) - )} +
+
+ {/* Time Filter */} +
+
+ {["This Week", "This Month", "This Year", "All Time"].map( + (filter) => ( + + ) + )} +
+ +
+
+ + to + +
+ +
-
- - to - - + {/* Stats Grid */} +
+ + +
Total Books
+
+ {stats.totalBooks} +
+
+
+ + +
Approved
+
+ {stats.approved} +
+
+
+ + +
+ Pending Approval +
+
+ {stats.pendingApproval} +
+
+
+ + +
Rejected
+
+ {stats.rejected} +
+
+
+ + +
Reported
+
+ {stats.reported} +
+
+
+ + +
Unpublished
+
+ {stats.unpublished} +
+
+
+ + +
+ NFT Edition Validated +
+
+ {stats.nftEditionValidated} +
+
+
+ + +
Approved
+
+ {stats.approvedStats} +
+
+
- {/* Stats Grid */} -
- - -
Total Books
-
- {stats.totalBooks} -
-
-
- - -
Approved
-
- {stats.approved} -
-
-
- - -
+ {/* Tabs */} + setActiveTab(value as TabType)} + className="bg-white rounded-lg border border-[#E7E7E7] p-4" + > +
+ + + All Books + + Pending Approval + + 27 + + + + Reported Content + + + +
+
+ +
-
- {stats.pendingApproval} -
- - - - -
Rejected
-
- {stats.rejected} -
-
-
- - -
Reported
-
- {stats.reported} -
-
-
- - -
Unpublished
-
- {stats.unpublished} -
-
-
- - -
- NFT Edition Validated -
-
- {stats.nftEditionValidated} -
-
-
- - -
Approved
-
- {stats.approvedStats} +
+ + + + + + e.preventDefault()}> + Date Submitted + + e.preventDefault()}> + Title + + e.preventDefault()}> + Author + + + + + + + + + e.preventDefault()} + > + Regular + + e.preventDefault()} + > + NFT Edition + + +
- - -
-
- - {/* Tabs */} - setActiveTab(value as TabType)} - className="bg-white rounded-lg border border-[#E7E7E7] p-4" - > -
- - - All Books - - - Pending Approval - - 27 - - - - Reported Content - - - -
-
- -
- - - - - - e.preventDefault()}> - Date Submitted - - e.preventDefault()}> - Title - - e.preventDefault()}> - Author - - - - - - - - - e.preventDefault()} - > - Regular - - e.preventDefault()} - > - NFT Edition - - -
-
- - {renderBookTable( - mockBooks.filter((book) => book.status === "Approved"), - "all-books" - )} - - - - {renderBookTable( - mockBooks.filter((book) => book.status === "Pending"), - "pending-approval" - )} - - - - {renderBookTable( - mockBooks.filter( - (book) => - book.status === "Unresolved" || book.status === "Resolved" - ), - "reported-content" - )} - - -
- Showing 1 to 10 of 107 - -
-
+ + {renderBookTable( + mockBooks.filter((book) => book.status === "Approved"), + "all-books" + )} + + + + {renderBookTable( + mockBooks.filter((book) => book.status === "Pending"), + "pending-approval" + )} + + + + {renderBookTable( + mockBooks.filter( + (book) => + book.status === "Unresolved" || book.status === "Resolved" + ), + "reported-content" + )} + + +
+ Showing 1 to 10 of 107 + +
+ +
); @@ -631,13 +676,13 @@ export default function ChainLibContentManagement() { return (
- +
{getTableHeaders().map((header, index) => ( @@ -647,18 +692,20 @@ export default function ChainLibContentManagement() { {books.map((book) => ( - - @@ -784,350 +831,997 @@ export default function ChainLibContentManagement() { if (!selectedBook) return null; return ( -
- {/* Header */} -
-
- -
-
- - - AL - -
-
Anna Loop
-
anna***p@gmail.com
+ + } + /> + +
+ {/* Book Info */} +
+
+
+
+ +
+
+
+

+ Native Invisibility +

+
+

By Darrin Collins

+ + + +
+ +
+
+ + + {selectedBook.rating || 4.5} + +
+
+
+
+
+ +
+ + {currentView === "book-approval" && ( +
+ + +
+ )} + {currentView == "book-details" && ( + + )} +
-
-
- {/* Book Info */} -
-
- {selectedBook.title} + {currentView == "book-approval" && ( + + )} + {/* Book Details Grid */} +
+
+
Payment Type
+
One-Time Payment
+
+
+
Price
+
+ {selectedBook.price || "N/A"} +
+
+
+
Published Date
+
+ {selectedBook.dateSubmitted} +
+
+
+
Sold
+
+ {selectedBook.sold || "N/A"} +
+
+
-
-
-

- {selectedBook.title} -

-

By {selectedBook.author}

- {selectedBook.rating && ( -
-
- - - {selectedBook.rating} - + + {/* Description */} +
+
+

+ Description +

+

+ Delves into the complex and often insidious ways in which + indigenous peoples and their unique experiences are rendered + unseen and unheard in the modern era. +

+ +
+ + {/* Additional Info */} +
+
+
Genre(s)
+
+
+ Fiction +
+
+ Comic
- )} +
+
+
Page count
+
+ {selectedBook.pageCount || "21 Pages"} +
+
+
+
Language
+
+ {selectedBook.language || "English"} +
+
+
+
Published Date
+
+ {selectedBook.dateSubmitted || "21 April 2025"} +
+
+
+
ISBN
+
+ {selectedBook.isbn || "ISBN: 978-3-16-148410-0"} +
+
+
- {currentView === "book-approval" && ( -
- + + + -
- )} - -
-
+
+ + +
Read
+
+
+ 192 +
+
+ -10% +
+
+
+
- {/* Book Details Grid */} -
-
-
Payment Type
-
One-Time Payment
-
-
-
Price
-
{selectedBook.price || "N/A"}
-
-
-
Published Date
-
{selectedBook.dateSubmitted}
-
-
-
Sold
-
{selectedBook.sold || "N/A"}
+ + +
+ Read Completion Rate +
+
+
+ 75% +
+
+ +5% +
+
+
+
+ + + +
Purchase
+
+
62
+
+ +8% +
+
+
+
+ + +
+ Total Complete Read +
+
70%
+
+
+ + +
+ Total Earning +
+
+ {" "} + 370.00 +
+
+
+ + +
+ Average Rating +
+
+ + 3.5 +
+
+
+
+
-
- {/* Description */} -
-

Description

-

- Delves into the complex and often insidious ways in which indigenous - peoples and their unique experiences are rendered unseen and unheard - in the modern era. -

- -
+ {/* Reviews Section */} +
+

+ Reviews and Rating +

- {/* Additional Info */} -
-
-
Genre(s)
-
- {selectedBook.genre?.map((g) => ( - - {g} - +
+
+
+ 3.5 +
+
+ {[1, 2, 3, 4, 5].map((star) => ( + + ))} +
+
+ 1202 Reviews +
+
+ +
+ {[5, 4, 3, 2, 1].map((rating) => ( +
+ {rating} + +
+ ))} +
+ + {/*
+
+
*/} +
+ + {/* Individual Reviews */} +
+ {[1, 2, 3, 4, 5, 6].map((review) => ( + + +
+
+ + + AS + + Adeja Samad +
+ +
+
+
+ {[1, 2, 3, 4].map((star) => ( + + ))} + +
+ + Yesterday + +
+ +

+ This was a great read, and I was hooked. However, the + death of my favorite character impacted my overall + enjoyment, which is why I'm rating it 4 stars instead + of 5. +

+ +
+
+ + {/* Footer aligned at the bottom */} +
+ + Author Replied + • 1 Reply +
+
+
))}
-
-
Page count
-
{selectedBook.pageCount}
-
-
-
Language
-
{selectedBook.language}
-
-
-
ISBN
-
{selectedBook.isbn}
-
+ + {/* Reports Section (if applicable) */} + {currentView === "book-details" && + selectedBook.status !== "Approved" && ( +
+

Reports & Comments

+ +
+
+
+ + + LV + +
+
+ Lana Victor + + Yesterday + +
+
+ + Plagiarism and Inappropriate Content + +
+

+ Presenting someone else's work and used images, that + are unsuitable, offensive, harmful, disturbing, often + based on societal norms, legal standards, age +

+
+
+
+ +
+
+ + + SY + +
+
+ Samuel Yaro + + 5 June, 2025 + +
+
+ + Inappropriate Content + +
+

+ Unsuitable, offensive, harmful, disturbing, often + based on societal norms, legal standards, age +

+
+
+
+
+
+ )}
+
+ ); + }; - {/* Performance Stats */} -
-

Book Performance Stats

-
- - - - + const renderBookPendingApproval = () => { + if (!selectedBook) return null; + + return ( +
+
+ + + + Book Details + + } + /> +
+ {/* Book Info */} +
+
+
+
+ +
+
+
+

+ Native Invisibility +

+
+

By Darrin Collins

+ + + +
+ +
+
+ + + {selectedBook.rating || 4.5} + +
+
+
+
+
+ +
+ + {currentView === "book-approval" && ( +
+ + +
+ )} +
+
+ + {currentView == "book-approval" && ( + + )} + {/* Book Details Grid */} +
+
+
Payment Type
+
One-Time Payment
+
+
+
Price
+
+ {" "} + {selectedBook.price || "N/A"} +
+
+
+
Date Submitted
+
+ {selectedBook.dateSubmitted} +
+
+
+
Review Status
+
Pending
+
+
+ {/* Description */} +
+
+

+ Description +

+

+ Delves into the complex and often insidious ways in which + indigenous peoples and their unique experiences are rendered + unseen and unheard in the modern era. +

+ +
-
- - -
Read
-
192
-
-10%
-
-
- - -
- Read Completion Rate + {/* Additional Info */} +
+
+
Genre(s)
+
+
+ Fiction +
+
+ Comic +
-
75%
-
+5%
- - - - -
Purchase
-
62
-
+8%
-
-
- - -
Total Complete Read
-
70%
-
-
- - -
Total Earning
-
$ 370.00
-
-
- - -
Average Rating
-
- - 3.5 +
+
+
Page count
+
+ {selectedBook.pageCount || "21 Pages"}
- - +
+
+
Language
+
+ {selectedBook.language || "English"} +
+
+
+
Date Submitted
+
+ {selectedBook.dateSubmitted || "21 April 2025"} +
+
+
+
ISBN
+
+ {selectedBook.isbn || "ISBN: 978-3-16-148410-0"} +
+
+
+
+ ); + }; - {/* Reviews Section */} -
-

Reviews and Rating

- -
-
-
3.5
-
- {[1, 2, 3, 4, 5].map((star) => ( - { + if (!selectedBook) return null; + + return ( +
+
+ + + + Book Details + + } + /> +
+ {/* Book Info */} +
+
+
+
+ - ))} +
+
+
+

+ Native Invisibility +

+
+

By Darrin Collins

+ + + +
+ +
+
+ + + {selectedBook.rating || 4.5} + +
+
+
+
+
+ +
+ + {currentView === "book-approval" && ( +
+ + +
+ )} + {currentView === "reported-content" && ( +
+ + +
+ )}
-
1202 Reviews
-
- {[5, 4, 3, 2, 1].map((rating) => ( -
- {rating} - + {currentView == "reported-content" && ( + + )} + {/* Book Details Grid */} +
+
+
Payment Type
+
One-Time Payment
+
+
+
Price
+
+ {" "} + {selectedBook.price || "N/A"}
- ))} +
+
+
Published Date
+
+ {selectedBook.dateSubmitted} +
+
+
+
Sold
+
47
+
+
+
Transaction
+
+ +
All Transactions
+
+
- {/* Individual Reviews */} -
- {[1, 2, 3, 4, 5, 6].map((review) => ( -
-
- - - AS - -
-
- Adeja Samad -
- {[1, 2, 3, 4].map((star) => ( - - ))} - -
- Yesterday -
-

- This was a great read, and I was hooked. However, the - death of my favorite character impacted my overall - enjoyment, which is why I'm rating it 4 stars instead of - 5. -

-
- -
- - - AR - - - Author Replied - • 1 Reply -
-
+ {/* Description */} +
+
+

+ Description +

+

+ Delves into the complex and often insidious ways in which + indigenous peoples and their unique experiences are rendered + unseen and unheard in the modern era. +

+ +
+ + {/* Additional Info */} +
+
+
Genre(s)
+
+
+ Fiction +
+
+ Comic
- ))} +
+
Page count
+
+ {selectedBook.pageCount || "21 Pages"} +
+
+
+
Language
+
+ {selectedBook.language || "English"} +
+
+
+
Date Submitted
+
+ {selectedBook.dateSubmitted || "21 April 2025"} +
+
+
+
ISBN
+
+ {selectedBook.isbn || "ISBN: 978-3-16-148410-0"} +
+
+
-
- {/* Reports Section (if applicable) */} - {currentView === "book-details" && - selectedBook.status !== "Approved" && ( -
-

Reports & Comments

+ {/* Reports Section */} +
+

+ Reports & Comments +

-
-
-
+
+
+
+
LV -
-
- Lana Victor - Yesterday -
-
- - Plagiarism and Inappropriate Content - -
-

- Presenting someone else's work and used images, that are - unsuitable, offensive, harmful, disturbing, often based - on societal norms, legal standards, age -

+
+ Lana Victor + Yesterday
+
+ + {"Plagiarism and Inappropriate Content"} + +
+

+ Presenting someone else's work and used images, that are + unsuitable, offensive, harmful, disturbing, often based on + societal norms, legal standards, age +

+
-
-
+
+
+
SY -
-
+
+
Samuel Yaro - + 5 June, 2025
-
- - Inappropriate Content - -
-

- Unsuitable, offensive, harmful, disturbing, often based - on societal norms, legal standards, age -

+
+ + Inappropriate Content + +
+

+ Unsuitable, offensive, harmful, disturbing, often based on + societal norms, legal standards, age +

- )} +
+
); }; return ( -
-
+
+
{currentView === "dashboard" && renderDashboard()} - {(currentView === "book-details" || currentView === "book-approval") && - renderBookDetails()} + {currentView === "book-details" && renderBookDetails()} + {currentView === "book-approval" && renderBookPendingApproval()} + {currentView === "reported-content" && renderReportedContent()}
+ + {/* Reject Modal */} + {isRejectModalOpen && ( +
+
+
+

+ Reject Publication +

+ +
+ +

+ Enter the reason you are rejecting this book for publication +

+ +
+

+ Rejected by: Ola**p@gmail.com +

+
+ +
+ +
{header}
- + {"Book -
+
+
{book.title}
-
+
by {book.author}