diff --git a/public/message_icon.png b/public/message_icon.png new file mode 100644 index 0000000..f979d66 Binary files /dev/null and b/public/message_icon.png differ diff --git a/src/app/dashboard/admin/user-management/page.tsx b/src/app/dashboard/admin/user-management/page.tsx index b2bd5e4..7d45fd3 100644 --- a/src/app/dashboard/admin/user-management/page.tsx +++ b/src/app/dashboard/admin/user-management/page.tsx @@ -1,20 +1,260 @@ -"use-client"; +"use client"; + +import React from "react"; +import { useState } from "react"; import { Header } from "@/components/dashboard/header"; +import { useRouter } from "next/navigation"; + +import { + Users, + UserCheck, + BookOpen, + UserPlus, + Search, + Filter, + SortAsc, +} from "lucide-react"; + +const UserManagment = () => { + const [activeTab, setActiveTab] = useState("Readers"); + const [searchTerm, setSearchTerm] = useState(""); + const router = useRouter(); + + const statsCards = [ + { title: "Writers", value: "257", icon: Users, bgColor: "bg-white" }, + { + title: "Verified Writers", + value: "83", + icon: UserCheck, + bgColor: "bg-white", + }, + { title: "Readers", value: "1093", icon: BookOpen, bgColor: "bg-white" }, + { + title: "Subscribed Readers", + value: "204", + icon: UserPlus, + bgColor: "bg-white", + }, + ]; + + const additionalStats = [ + { title: "Total Users", value: "257", icon: Users, bgColor: "bg-white" }, + ]; + const readersData = [ + { + name: "Jane Doe", + wallet: "0xABC...789", + joinedDate: "27 May, 2025", + booksPurchased: 13, + readingRank: "Bookworm", + }, + { + name: "Ole Paul", + wallet: "0xABC...789", + joinedDate: "7 June, 2025", + booksPurchased: 3, + readingRank: "Enthusiast", + }, + { + name: "Aminu Sani", + wallet: "0xABC...789", + joinedDate: "27 May, 2025", + booksPurchased: 9, + readingRank: "Scholar", + }, + { + name: "Faith Adamu", + wallet: "0xABC...789", + joinedDate: "7 June, 2025", + booksPurchased: 11, + readingRank: "Connoisseur", + }, + { + name: "Wood Word", + wallet: "0xABC...789", + joinedDate: "27 May, 2025", + booksPurchased: 4, + readingRank: "Scholar", + }, + ]; -export default function UserManagment() { + type StatCardProps = { + title: string; + value: string; + icon: React.ElementType; + bgColor: string; + }; + + const StatCard: React.FC = ({ title, value, icon: Icon, bgColor }) => ( +
+
+
+

{title}

+

{value}

+
+
+ +
+
+
+ ); return ( <> -
-
-
-

User Management

-

- Welcome to user management section of the admin dashboard! Here, you can manage all aspects of user accounts, including registration, profiles, and permissions. This space is designed to help you maintain a secure and organized user base, ensuring that users have the appropriate access and capabilities within your platform. -

+
+ +
+
+ {/* Stats Cards Grid */} +
+ {statsCards.map((card, index) => ( + + ))} +
+ + {/* Additional Stats Row */} +
+ {additionalStats.map((card, index) => ( + + ))} + {/* Empty placeholders for consistent grid */} +
+
+
+
+ + {/* Main Content Area */} +
+ {/* Tab Navigation */} +
+
+
+ {["Readers", "Writers"].map((tab) => ( + + ))} +
+ + {/* Search and Filter Controls */} +
+
+ + setSearchTerm(e.target.value)} + className="pl-10 pr-4 py-2 border border-gray-300 rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent w-full sm:w-64" + /> +
+ + +
+
+
+ + {/* Table */} +
+ + + + + + + + + + + + + {readersData + .filter((reader) => + reader.name + .toLowerCase() + .includes(searchTerm.toLowerCase()) + ) + .map((reader, index) => ( + router.push(`/dashboard/admin/user-management/readers/${encodeURIComponent(reader.name)}`)} + > + + + + + + + + ))} + +
+ Reader Name + + Wallet Address + + Joined Date + + Books Purchased + + Reading Rank + + Action +
+ {reader.name} + + {reader.wallet} + + {reader.joinedDate} + + {reader.booksPurchased} + + {reader.readingRank} + + +
+
+ + {/* Pagination */} +
+
+ Showing 1 to 5 of 12 +
+ +
+
); -} +}; + +export default UserManagment; diff --git a/src/app/dashboard/admin/user-management/readers/[id]/page.tsx b/src/app/dashboard/admin/user-management/readers/[id]/page.tsx new file mode 100644 index 0000000..1fe69e7 --- /dev/null +++ b/src/app/dashboard/admin/user-management/readers/[id]/page.tsx @@ -0,0 +1,406 @@ +"use client"; + +import React, { useState } from "react"; +import { MessageCircle, Star, BookOpen } from "lucide-react"; +import { useParams } from "next/navigation"; +import Image from "next/image"; + +import { Header } from "@/components/dashboard/header"; +import reader1_img from "@/assets/images/reader1.png"; + +import { Search } from "lucide-react"; + +import SuspendUserModal from "@/components/reader/SuspendUserModal"; + +type Reader = { + name: string; + wallet: string; + joinedDate: string; + readingRank: string; + image: string; +}; + +const mockReaders: { [key: string]: Reader } = { + "Jane Doe": { + name: "Jane Doe", + wallet: "0xABC...789", + joinedDate: "27 May, 2025", + readingRank: "Bookworm", + image: "/api/placeholder/64/64", + }, + "Ole Paul": { + name: "Ole Paul", + wallet: "0xABC...789", + joinedDate: "7 June, 2025", + readingRank: "Enthusiast", + image: "/api/placeholder/64/64", + }, + "Aminu Sani": { + name: "Aminu Sani", + wallet: "0xABC...789", + joinedDate: "27 May, 2025", + readingRank: "Scholar", + image: "/api/placeholder/64/64", + }, + "Faith Adamu": { + name: "Faith Adamu", + wallet: "0xABC...789", + joinedDate: "7 June, 2025", + readingRank: "Connoisseur", + image: "/api/placeholder/64/64", + }, + "Wood Word": { + name: "Wood Word", + wallet: "0xABC...789", + joinedDate: "27 May, 2025", + readingRank: "Scholar", + image: "/api/placeholder/64/64", + }, +}; + +const UserProfilePage = () => { + const params = useParams(); + const readerId = decodeURIComponent(params.id as string); + const reader = mockReaders[readerId] || mockReaders["Jane Doe"]; + const [suspendModalOpen, setSuspendModalOpen] = useState(false); + + const [activeTab, setActiveTab] = useState("Library"); + const [activeFilter, setActiveFilter] = useState("All"); + + const setShowModal = (show: boolean) => { + setSuspendModalOpen(show); + } + + const stats = [ + { label: "Following", value: "4", color: "text-blue-600" }, + { + label: "Average Session", + value: "45", + unit: "Minutes", + color: "text-blue-600", + }, + { + label: "Completion Rate", + value: "4", + unit: "Hours", + color: "text-blue-600", + }, + { + label: "Last Seen", + value: "14", + unit: "Hours Ago", + color: "text-blue-600", + }, + ]; + + const libraryStats = [ + { label: "Total Books Purchased", value: "24" }, + { label: "Regular Book", value: "12" }, + { label: "NFT Editions", value: "4" }, + { label: "Series", value: "8" }, + { label: "Collections", value: "3" }, + { label: "Read", value: "3" }, + { label: "Progress", value: "3" }, + { label: "Unread", value: "3" }, + ]; + + const books = [ + { + id: 1, + title: "Native Invisibility", + author: "Danni Collins", + rating: 4.5, + image: "/api/placeholder/80/120", + isNFT: false, + views: null, + }, + { + id: 2, + title: "Native Invisibility", + author: "Danni Collins", + rating: 4.5, + image: "/api/placeholder/80/120", + isNFT: false, + views: 4, + }, + { + id: 3, + title: "Native Invisibility", + author: "Danni Collins", + rating: 4.5, + image: "/api/placeholder/80/120", + isNFT: true, + views: null, + }, + { + id: 4, + title: "Native Invisibility", + author: "Danni Collins", + rating: 4.5, + image: "/api/placeholder/80/120", + isNFT: false, + views: 4, + }, + { + id: 5, + title: "Native Invisibility", + author: "Danni Collins", + rating: 4.5, + image: "/api/placeholder/80/120", + isNFT: false, + views: null, + }, + { + id: 6, + title: "Native Invisibility", + author: "Danni Collins", + rating: 4.5, + image: "/api/placeholder/80/120", + isNFT: false, + views: 4, + }, + { + id: 7, + title: "Native Invisibility", + author: "Danni Collins", + rating: 4.5, + image: "/api/placeholder/80/120", + isNFT: false, + views: null, + }, + { + id: 8, + title: "Native Invisibility", + author: "Danni Collins", + rating: 4.5, + image: "/api/placeholder/80/120", + isNFT: true, + views: null, + }, + ]; + + type Book = { + id: number; + title: string; + author: string; + rating: number; + image: string; + isNFT: boolean; + views: number | null; + }; + + const BookCard = ({ book }: { book: Book }) => ( +
+ {book.isNFT && ( +
+ NFT +
+ )} +
+ {book.title} +
+

+ {book.title} +

+
+

By {book.author}

+ Verified Icon +
+
+ + {book.rating} + {book.views && ( + <> + + {book.views} + + )} +
+
+
+
+ ); + + return ( + <> +
+ {suspendModalOpen &&
+ +
} +
+
+ {/* Header Section */} +
+
+
+
+ {reader.name} +
+
+

+ {reader.name} +

+
+

{reader.wallet}

+ Copy Wallet Address +
+
+ Rank: + + {reader.readingRank} + +
+

+ Joined: {reader.joinedDate} +

+
+
+
+ + +
+
+ + {/* Stats Grid */} +
+ {stats.map((stat, index) => ( +
+
+ {stat.label} +
+ +
+ {stat.value} + {stat.unit && ( + + {stat.unit} + + )} +
+
+ ))} +
+
+ + {/* Main Content */} +
+ {/* Tab Navigation */} +
+
+ {[ + "Library", + "Transactions", + "Direct Notification", + "Reviews & Feedback", + ].map((tab) => ( + + ))} +
+
+ + {/* Library Content */} + {activeTab === "Library" && ( +
+ {/* Library Stats */} +
+ {libraryStats.map((stat, index) => ( +
+
{stat.label}
+ +
+ {stat.value} +
+
+ ))} +
+ + {/* Filter Tabs */} +
+
+ {["All", "Regular", "NFT Edition", "Series"].map( + (filter) => ( + + ) + )} +
+
+ + +
+
+ + {/* Books Grid */} +
+ {books.map((book) => ( + + ))} +
+
+ )} + + {/* Other Tab Contents */} + {activeTab !== "Library" && ( +
+
+ {activeTab} content would go here +
+
+ )} +
+
+
+ + ); +}; + +export default UserProfilePage; diff --git a/src/assets/images/reader1.png b/src/assets/images/reader1.png new file mode 100644 index 0000000..1af3439 Binary files /dev/null and b/src/assets/images/reader1.png differ diff --git a/src/components/reader/SuspendUserModal.tsx b/src/components/reader/SuspendUserModal.tsx new file mode 100644 index 0000000..ae2b646 --- /dev/null +++ b/src/components/reader/SuspendUserModal.tsx @@ -0,0 +1,160 @@ +import React, { useState } from "react"; +import { X, ChevronDown } from "lucide-react"; + +type SuspendUserModalProps = { + setShow: (show: boolean) => void; +}; + +export default function SuspendUserModal({ setShow }: SuspendUserModalProps) { + const [reason, setReason] = useState(""); + const [duration, setDuration] = useState(""); + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(true); + + const durationOptions = [ + "1 Day", + "3 Days", + "1 Week", + "2 Weeks", + "1 Month", + "3 Months", + "6 Months", + "1 Year", + "Permanent", + ]; + + const handleDurationSelect = (selectedDuration: any) => { + setDuration(selectedDuration); + setIsDropdownOpen(false); + }; + + const handleSuspend = () => { + console.log( + "Suspending user with reason:", + reason, + "and duration:", + duration + ); + // Add your suspension logic here + }; + + const handleCancel = () => { + setIsModalOpen(false); + }; + + if (!isModalOpen) { + return ( +
+ +
+ ); + } + + return ( +
+
+ {/* Header */} +
+

Suspend User

+ +
+ + {/* Content */} +
+ {/* Blue info box */} +
+

+ Enter the reason you are suspending these user +

+
+ + {/* Suspended by info */} +
+

+ Suspended by:{" "} + Ola***p@gmail.com +

+
+ + {/* Description field */} +
+ +