1- ' use client' ;
1+ " use client" ;
22
3- import React , { useState , useEffect } from 'react' ;
4- import {
5- Users ,
6- Shield ,
7- TrendingUp ,
8- Activity ,
9- ArrowUpRight ,
10- ArrowDownRight ,
11- BarChart3 ,
12- Wallet ,
13- UserPlus ,
14- CheckCircle2 ,
15- Loader2 ,
16- } from 'lucide-react' ;
17- import { AdminService } from '@/services/admin' ;
18- import { IPlatformStats } from '@/types/admin' ;
3+ import React , { useState , useEffect } from "react" ;
4+ import { Users , Shield , TrendingUp , Activity , ArrowUpRight , ArrowDownRight , BarChart3 , Wallet , UserPlus , CheckCircle2 } from "lucide-react" ;
5+ import { AdminService } from "@/services/admin" ;
6+ import { IPlatformStats } from "@/types/admin" ;
7+ import { AdminOverviewSkeleton } from "@/components/ui/AdminOverviewSkeleton" ;
198
209function StatCard ( {
2110 title,
@@ -35,41 +24,29 @@ function StatCard({
3524 const isPositive = change && change > 0 ;
3625 return (
3726 < div className = "relative group" >
38- < div className = "absolute -inset-[1px] bg-gradient-to-r opacity-0 group-hover:opacity-100 rounded-xl transition-opacity duration-500 blur-sm"
27+ < div
28+ className = "absolute -inset-[1px] bg-gradient-to-r opacity-0 group-hover:opacity-100 rounded-xl transition-opacity duration-500 blur-sm"
3929 style = { { backgroundImage : gradient } }
4030 />
4131 < div className = "relative bg-[#12121a] border border-white/5 rounded-xl p-5 hover:border-white/10 transition-all duration-300" >
4232 < div className = "flex items-start justify-between mb-4" >
43- < div
44- className = "w-10 h-10 rounded-lg flex items-center justify-center"
45- style = { { background : gradient } }
46- >
33+ < div className = "w-10 h-10 rounded-lg flex items-center justify-center" style = { { background : gradient } } >
4734 < Icon className = "w-5 h-5 text-white" />
4835 </ div >
4936 { change !== undefined && (
5037 < div
5138 className = { `flex items-center gap-1 text-xs font-medium px-2 py-1 rounded-full ${
52- isPositive
53- ? 'bg-emerald-500/10 text-emerald-400'
54- : 'bg-red-500/10 text-red-400'
39+ isPositive ? "bg-emerald-500/10 text-emerald-400" : "bg-red-500/10 text-red-400"
5540 } `}
5641 >
57- { isPositive ? (
58- < ArrowUpRight className = "w-3 h-3" />
59- ) : (
60- < ArrowDownRight className = "w-3 h-3" />
61- ) }
42+ { isPositive ? < ArrowUpRight className = "w-3 h-3" /> : < ArrowDownRight className = "w-3 h-3" /> }
6243 { Math . abs ( change ) } %
6344 </ div >
6445 ) }
6546 </ div >
66- < p className = "text-2xl font-bold text-white mb-1" >
67- { typeof value === 'number' ? value . toLocaleString ( ) : value }
68- </ p >
47+ < p className = "text-2xl font-bold text-white mb-1" > { typeof value === "number" ? value . toLocaleString ( ) : value } </ p >
6948 < p className = "text-xs text-gray-500" > { title } </ p >
70- { changeLabel && (
71- < p className = "text-[10px] text-gray-600 mt-1" > { changeLabel } </ p >
72- ) }
49+ { changeLabel && < p className = "text-[10px] text-gray-600 mt-1" > { changeLabel } </ p > }
7350 </ div >
7451 </ div >
7552 ) ;
@@ -78,9 +55,9 @@ function StatCard({
7855function RoleDistribution ( { roles } : { roles : Record < string , number > } ) {
7956 const total = Object . values ( roles ) . reduce ( ( a , b ) => a + b , 0 ) ;
8057 const colors : Record < string , string > = {
81- USER : ' #8b5cf6' ,
82- ADMIN : ' #3b82f6' ,
83- SUPER_ADMIN : ' #06b6d4' ,
58+ USER : " #8b5cf6" ,
59+ ADMIN : " #3b82f6" ,
60+ SUPER_ADMIN : " #06b6d4" ,
8461 } ;
8562
8663 return (
@@ -95,9 +72,7 @@ function RoleDistribution({ roles }: { roles: Record<string, number> }) {
9572 return (
9673 < div key = { role } >
9774 < div className = "flex items-center justify-between mb-1.5" >
98- < span className = "text-xs text-gray-400 capitalize" >
99- { role . replace ( '_' , ' ' ) . toLowerCase ( ) }
100- </ span >
75+ < span className = "text-xs text-gray-400 capitalize" > { role . replace ( "_" , " " ) . toLowerCase ( ) } </ span >
10176 < span className = "text-xs text-gray-300 font-medium" >
10277 { count . toLocaleString ( ) } ({ pct . toFixed ( 1 ) } %)
10378 </ span >
@@ -107,7 +82,7 @@ function RoleDistribution({ roles }: { roles: Record<string, number> }) {
10782 className = "h-full rounded-full transition-all duration-1000 ease-out"
10883 style = { {
10984 width : `${ pct } %` ,
110- backgroundColor : colors [ role ] || ' #8b5cf6' ,
85+ backgroundColor : colors [ role ] || " #8b5cf6" ,
11186 } }
11287 />
11388 </ div >
@@ -121,7 +96,7 @@ function RoleDistribution({ roles }: { roles: Record<string, number> }) {
12196
12297function EscrowVolumeChart ( ) {
12398 // Simulated chart data
124- const months = [ ' Oct' , ' Nov' , ' Dec' , ' Jan' , ' Feb' , ' Mar' ] ;
99+ const months = [ " Oct" , " Nov" , " Dec" , " Jan" , " Feb" , " Mar" ] ;
125100 const values = [ 320 , 480 , 560 , 720 , 610 , 850 ] ;
126101 const max = Math . max ( ...values ) ;
127102
@@ -137,9 +112,7 @@ function EscrowVolumeChart() {
137112 const height = ( values [ i ] / max ) * 100 ;
138113 return (
139114 < div key = { month } className = "flex-1 flex flex-col items-center gap-2" >
140- < span className = "text-[10px] text-gray-500 font-medium" >
141- { values [ i ] }
142- </ span >
115+ < span className = "text-[10px] text-gray-500 font-medium" > { values [ i ] } </ span >
143116 < div className = "w-full relative rounded-t-md overflow-hidden" style = { { height : `${ height } %` } } >
144117 < div
145118 className = "absolute inset-0 rounded-t-md transition-all duration-700 ease-out"
@@ -159,11 +132,11 @@ function EscrowVolumeChart() {
159132
160133function RecentActivity ( ) {
161134 const activities = [
162- { type : ' escrow_created' , desc : 'New escrow created: "Website Dev"' , time : ' 5m ago' , icon : Shield } ,
163- { type : ' user_joined' , desc : ' New user registered: GAX3...' , time : ' 12m ago' , icon : UserPlus } ,
164- { type : ' escrow_completed' , desc : 'Escrow completed: "API Integration"' , time : ' 28m ago' , icon : CheckCircle2 } ,
165- { type : ' user_joined' , desc : ' New user registered: GBK2...' , time : ' 1h ago' , icon : UserPlus } ,
166- { type : ' escrow_created' , desc : 'New escrow created: "DeFi Audit"' , time : ' 2h ago' , icon : Shield } ,
135+ { type : " escrow_created" , desc : 'New escrow created: "Website Dev"' , time : " 5m ago" , icon : Shield } ,
136+ { type : " user_joined" , desc : " New user registered: GAX3..." , time : " 12m ago" , icon : UserPlus } ,
137+ { type : " escrow_completed" , desc : 'Escrow completed: "API Integration"' , time : " 28m ago" , icon : CheckCircle2 } ,
138+ { type : " user_joined" , desc : " New user registered: GBK2..." , time : " 1h ago" , icon : UserPlus } ,
139+ { type : " escrow_created" , desc : 'New escrow created: "DeFi Audit"' , time : " 2h ago" , icon : Shield } ,
167140 ] ;
168141
169142 return (
@@ -203,14 +176,7 @@ export default function AdminOverviewPage() {
203176 } , [ ] ) ;
204177
205178 if ( loading ) {
206- return (
207- < div className = "flex items-center justify-center min-h-[60vh]" >
208- < div className = "flex flex-col items-center gap-3" >
209- < Loader2 className = "w-8 h-8 text-purple-500 animate-spin" />
210- < p className = "text-sm text-gray-500" > Loading dashboard...</ p >
211- </ div >
212- </ div >
213- ) ;
179+ return < AdminOverviewSkeleton /> ;
214180 }
215181
216182 if ( ! stats ) return null ;
@@ -220,9 +186,7 @@ export default function AdminOverviewPage() {
220186 { /* Page header */ }
221187 < div >
222188 < h1 className = "text-2xl font-bold text-white" > Platform Overview</ h1 >
223- < p className = "text-sm text-gray-500 mt-1" >
224- Real-time platform statistics and monitoring
225- </ p >
189+ < p className = "text-sm text-gray-500 mt-1" > Real-time platform statistics and monitoring</ p >
226190 </ div >
227191
228192 { /* Stats grid */ }
@@ -278,34 +242,19 @@ export default function AdminOverviewPage() {
278242 </ h3 >
279243 < div className = "grid grid-cols-2 gap-4" >
280244 < div className = "bg-white/[0.02] rounded-lg p-4" >
281- < p className = "text-2xl font-bold text-white" >
282- { stats . users . active . toLocaleString ( ) }
283- </ p >
245+ < p className = "text-2xl font-bold text-white" > { stats . users . active . toLocaleString ( ) } </ p >
284246 < p className = "text-xs text-gray-500 mt-1" > Active Users</ p >
285247 </ div >
286248 < div className = "bg-white/[0.02] rounded-lg p-4" >
287- < p className = "text-2xl font-bold text-white" >
288- { stats . escrows . total . toLocaleString ( ) }
289- </ p >
249+ < p className = "text-2xl font-bold text-white" > { stats . escrows . total . toLocaleString ( ) } </ p >
290250 < p className = "text-xs text-gray-500 mt-1" > Total Escrows</ p >
291251 </ div >
292252 < div className = "bg-white/[0.02] rounded-lg p-4" >
293- < p className = "text-2xl font-bold text-white" >
294- { (
295- ( stats . escrows . completed / Math . max ( stats . escrows . total , 1 ) ) *
296- 100
297- ) . toFixed ( 1 ) }
298- %
299- </ p >
253+ < p className = "text-2xl font-bold text-white" > { ( ( stats . escrows . completed / Math . max ( stats . escrows . total , 1 ) ) * 100 ) . toFixed ( 1 ) } %</ p >
300254 < p className = "text-xs text-gray-500 mt-1" > Completion Rate</ p >
301255 </ div >
302256 < div className = "bg-white/[0.02] rounded-lg p-4" >
303- < p className = "text-2xl font-bold text-white" >
304- { Math . round (
305- stats . volume . totalCompleted /
306- Math . max ( stats . escrows . completed , 1 )
307- ) . toLocaleString ( ) }
308- </ p >
257+ < p className = "text-2xl font-bold text-white" > { Math . round ( stats . volume . totalCompleted / Math . max ( stats . escrows . completed , 1 ) ) . toLocaleString ( ) } </ p >
309258 < p className = "text-xs text-gray-500 mt-1" > Avg Volume (XLM)</ p >
310259 </ div >
311260 </ div >
0 commit comments