@@ -6,6 +6,7 @@ import type { BuybackCampaignModel } from '../../types/campaign';
66import { useProjectionRefresh } from '../../hooks/useProjectionRefresh' ;
77import { campaignApi } from '../../services/campaignApi' ;
88import { getTxUrl } from '../../utils/explorer' ;
9+ import { Skeleton } from '../UI/Skeleton' ;
910
1011const BACKEND_URL = import . meta. env . VITE_BACKEND_URL ?? '' ;
1112
@@ -68,12 +69,37 @@ export const CampaignDashboard: React.FC<CampaignDashboardProps> = ({
6869
6970 if ( loading ) {
7071 return (
71- < div className = "flex items-center justify-center p-8" >
72- < div
73- role = "status"
74- aria-label = "Loading"
75- className = "animate-spin rounded-full h-12 w-12 border-b-2 border-purple-600"
76- />
72+ < div className = "max-w-4xl mx-auto p-6 space-y-6" aria-label = "Loading campaign" >
73+ < div className = "bg-white rounded-lg shadow-lg p-6" >
74+ { /* Header row */ }
75+ < div className = "flex items-center justify-between mb-6" >
76+ < Skeleton className = "h-8" width = "40%" />
77+ < Skeleton variant = "rectangular" width = { 80 } height = { 32 } />
78+ </ div >
79+ { /* Meta grid */ }
80+ < div className = "grid grid-cols-2 gap-4 mb-6" >
81+ { [ ...Array ( 4 ) ] . map ( ( _ , i ) => (
82+ < div key = { i } >
83+ < Skeleton className = "mb-1 h-3" width = "50%" />
84+ < Skeleton width = "70%" />
85+ </ div >
86+ ) ) }
87+ </ div >
88+ { /* Progress bar area */ }
89+ < div className = "mb-6" >
90+ < div className = "flex justify-between mb-2" >
91+ < Skeleton width = { 60 } />
92+ < Skeleton width = { 30 } />
93+ </ div >
94+ < Skeleton variant = "rectangular" height = { 12 } />
95+ </ div >
96+ { /* Steps list */ }
97+ < div className = "space-y-3" >
98+ { [ ...Array ( 3 ) ] . map ( ( _ , i ) => (
99+ < Skeleton key = { i } variant = "rectangular" height = { 64 } />
100+ ) ) }
101+ </ div >
102+ </ div >
77103 </ div >
78104 ) ;
79105 }
0 commit comments