Skip to content

Commit a95ed20

Browse files
authored
Feature/readers user management (#77)
* ui: add user management root * feat: add comprehensive reader user management system with access control, analytics, and subscription features
1 parent 97be18e commit a95ed20

5 files changed

Lines changed: 816 additions & 10 deletions

File tree

public/message_icon.png

801 Bytes
Loading
Lines changed: 250 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,260 @@
1-
"use-client";
1+
"use client";
2+
3+
import React from "react";
4+
import { useState } from "react";
25
import { Header } from "@/components/dashboard/header";
6+
import { useRouter } from "next/navigation";
7+
8+
import {
9+
Users,
10+
UserCheck,
11+
BookOpen,
12+
UserPlus,
13+
Search,
14+
Filter,
15+
SortAsc,
16+
} from "lucide-react";
17+
18+
const UserManagment = () => {
19+
const [activeTab, setActiveTab] = useState("Readers");
20+
const [searchTerm, setSearchTerm] = useState("");
21+
const router = useRouter();
22+
23+
const statsCards = [
24+
{ title: "Writers", value: "257", icon: Users, bgColor: "bg-white" },
25+
{
26+
title: "Verified Writers",
27+
value: "83",
28+
icon: UserCheck,
29+
bgColor: "bg-white",
30+
},
31+
{ title: "Readers", value: "1093", icon: BookOpen, bgColor: "bg-white" },
32+
{
33+
title: "Subscribed Readers",
34+
value: "204",
35+
icon: UserPlus,
36+
bgColor: "bg-white",
37+
},
38+
];
39+
40+
const additionalStats = [
41+
{ title: "Total Users", value: "257", icon: Users, bgColor: "bg-white" },
42+
];
343

44+
const readersData = [
45+
{
46+
name: "Jane Doe",
47+
wallet: "0xABC...789",
48+
joinedDate: "27 May, 2025",
49+
booksPurchased: 13,
50+
readingRank: "Bookworm",
51+
},
52+
{
53+
name: "Ole Paul",
54+
wallet: "0xABC...789",
55+
joinedDate: "7 June, 2025",
56+
booksPurchased: 3,
57+
readingRank: "Enthusiast",
58+
},
59+
{
60+
name: "Aminu Sani",
61+
wallet: "0xABC...789",
62+
joinedDate: "27 May, 2025",
63+
booksPurchased: 9,
64+
readingRank: "Scholar",
65+
},
66+
{
67+
name: "Faith Adamu",
68+
wallet: "0xABC...789",
69+
joinedDate: "7 June, 2025",
70+
booksPurchased: 11,
71+
readingRank: "Connoisseur",
72+
},
73+
{
74+
name: "Wood Word",
75+
wallet: "0xABC...789",
76+
joinedDate: "27 May, 2025",
77+
booksPurchased: 4,
78+
readingRank: "Scholar",
79+
},
80+
];
481

5-
export default function UserManagment() {
82+
type StatCardProps = {
83+
title: string;
84+
value: string;
85+
icon: React.ElementType;
86+
bgColor: string;
87+
};
88+
89+
const StatCard: React.FC<StatCardProps> = ({ title, value, icon: Icon, bgColor }) => (
90+
<div
91+
className={`${bgColor} rounded-lg p-6 shadow-sm border border-gray-200`}
92+
>
93+
<div className="flex items-center justify-between">
94+
<div>
95+
<p className="text-sm font-medium text-gray-600">{title}</p>
96+
<p className="text-2xl font-bold text-gray-900 mt-1">{value}</p>
97+
</div>
98+
<div className="p-2 bg-gray-100 rounded-lg">
99+
<Icon className="h-6 w-6 text-gray-600" />
100+
</div>
101+
</div>
102+
</div>
103+
);
6104

7105
return (
8106
<>
9-
<Header title="User Managements" />
10-
<div className="space-y-6">
11-
<div className="flex flex-col items-center justify-center h-screen">
12-
<h1 className="text-2xl font-bold text-gray-800">User Management</h1>
13-
<p className="text-gray-600 mt-2">
14-
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.
15-
</p>
107+
<Header title="User Managements" />
108+
109+
<div className="min-h-screen bg-gray-50 p-4 md:p-6">
110+
<div className="w-full mx-auto">
111+
{/* Stats Cards Grid */}
112+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
113+
{statsCards.map((card, index) => (
114+
<StatCard key={index} {...card} />
115+
))}
116+
</div>
117+
118+
{/* Additional Stats Row */}
119+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
120+
{additionalStats.map((card, index) => (
121+
<StatCard key={index} {...card} />
122+
))}
123+
{/* Empty placeholders for consistent grid */}
124+
<div className="hidden lg:block"></div>
125+
<div className="hidden lg:block"></div>
126+
<div className="hidden lg:block"></div>
127+
</div>
128+
129+
{/* Main Content Area */}
130+
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
131+
{/* Tab Navigation */}
132+
<div className="border-b border-gray-200">
133+
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between p-4">
134+
<div className="flex space-x-1 mb-4 sm:mb-0">
135+
{["Readers", "Writers"].map((tab) => (
136+
<button
137+
key={tab}
138+
onClick={() => setActiveTab(tab)}
139+
className={`px-4 py-2 text-sm font-medium rounded-md transition-colors ${
140+
activeTab === tab
141+
? "bg-blue-600 text-white"
142+
: "text-gray-500 hover:text-gray-700"
143+
}`}
144+
>
145+
{tab}
146+
</button>
147+
))}
148+
</div>
149+
150+
{/* Search and Filter Controls */}
151+
<div className="flex flex-col sm:flex-row gap-2">
152+
<div className="relative">
153+
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
154+
<input
155+
type="text"
156+
placeholder="Search for a Reader"
157+
value={searchTerm}
158+
onChange={(e) => setSearchTerm(e.target.value)}
159+
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"
160+
/>
161+
</div>
162+
<button className="flex items-center gap-2 px-4 py-2 text-sm text-gray-600 border border-gray-300 rounded-md hover:bg-gray-50">
163+
<SortAsc className="h-4 w-4" />
164+
Sort
165+
</button>
166+
<button className="flex items-center gap-2 px-4 py-2 text-sm text-gray-600 border border-gray-300 rounded-md hover:bg-gray-50">
167+
<Filter className="h-4 w-4" />
168+
Filter
169+
</button>
170+
</div>
171+
</div>
172+
</div>
173+
174+
{/* Table */}
175+
<div className="overflow-x-auto">
176+
<table className="w-full">
177+
<thead className="bg-gray-50">
178+
<tr>
179+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
180+
Reader Name
181+
</th>
182+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
183+
Wallet Address
184+
</th>
185+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
186+
Joined Date
187+
</th>
188+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
189+
Books Purchased
190+
</th>
191+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
192+
Reading Rank
193+
</th>
194+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
195+
Action
196+
</th>
197+
</tr>
198+
</thead>
199+
<tbody className="bg-white divide-y divide-gray-200">
200+
{readersData
201+
.filter((reader) =>
202+
reader.name
203+
.toLowerCase()
204+
.includes(searchTerm.toLowerCase())
205+
)
206+
.map((reader, index) => (
207+
<tr
208+
key={index}
209+
className="hover:bg-gray-50 cursor-pointer"
210+
onClick={() => router.push(`/dashboard/admin/user-management/readers/${encodeURIComponent(reader.name)}`)}
211+
>
212+
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
213+
{reader.name}
214+
</td>
215+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
216+
{reader.wallet}
217+
</td>
218+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
219+
{reader.joinedDate}
220+
</td>
221+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
222+
{reader.booksPurchased}
223+
</td>
224+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
225+
{reader.readingRank}
226+
</td>
227+
<td className="px-6 py-4 whitespace-nowrap text-sm">
228+
<button
229+
className="text-blue-600 hover:text-blue-900 font-medium"
230+
onClick={e => {
231+
e.stopPropagation();
232+
router.push(`/dashboard/admin/user-management/readers/${encodeURIComponent(reader.name)}`);
233+
}}
234+
>
235+
View Profile
236+
</button>
237+
</td>
238+
</tr>
239+
))}
240+
</tbody>
241+
</table>
242+
</div>
243+
244+
{/* Pagination */}
245+
<div className="flex flex-col sm:flex-row items-center justify-between px-6 py-4 border-t border-gray-200">
246+
<div className="text-sm text-gray-500 mb-4 sm:mb-0">
247+
Showing 1 to 5 of 12
248+
</div>
249+
<button className="px-4 py-2 text-sm text-gray-600 border border-gray-300 rounded-md hover:bg-gray-50">
250+
View All
251+
</button>
252+
</div>
253+
</div>
16254
</div>
17255
</div>
18256
</>
19257
);
20-
}
258+
};
259+
260+
export default UserManagment;

0 commit comments

Comments
 (0)