33import { useSearchParams } from "next/navigation" ;
44import { useEffect , useState , Suspense } from "react" ;
55import { UniTable } from "@/components/UniTable" ;
6- import { SlidersHorizontal , MapPin , DollarSign , GraduationCap } from "lucide-react" ;
6+ import { SlidersHorizontal , MapPin , DollarSign , GraduationCap , Search , X , Sparkles } from "lucide-react" ;
77
88function CompareContent ( ) {
99 const searchParams = useSearchParams ( ) ;
10- // Strip wildcard values so API treats them as "show all"
1110 const rawCourse = searchParams . get ( "course" ) || "" ;
1211 const rawBudget = searchParams . get ( "budget" ) || "" ;
1312 const initialCourse = [ "any" , "Any" ] . includes ( rawCourse ) ? "" : rawCourse ;
@@ -16,8 +15,6 @@ function CompareContent() {
1615
1716 const [ data , setData ] = useState < any [ ] > ( [ ] ) ;
1817 const [ loading , setLoading ] = useState ( true ) ;
19-
20- // Filter states
2118 const [ course , setCourse ] = useState ( initialCourse ) ;
2219 const [ budget , setBudget ] = useState ( initialBudget ) ;
2320 const [ location , setLocation ] = useState ( initialLocation ) ;
@@ -34,94 +31,169 @@ function CompareContent() {
3431 setLoading ( false ) ;
3532 } ;
3633
37- useEffect ( ( ) => {
38- fetchResults ( ) ;
39- } , [ course , budget , location ] ) ; // Re-fetch when filters change
34+ useEffect ( ( ) => { fetchResults ( ) ; } , [ course , budget , location ] ) ;
35+
36+ const clearFilters = ( ) => { setCourse ( "" ) ; setBudget ( "" ) ; setLocation ( "Anywhere" ) ; } ;
37+ const hasFilters = course || budget || location !== "Anywhere" ;
4038
4139 return (
42- < div className = "flex flex-col md:flex-row gap-6 mt-10" >
43- < aside className = "w-full md:w-64 bg-white dark:bg-slate-900 border border-gray-100 dark:border-gray-800 rounded-2xl p-6 shadow-sm h-fit sticky top-24 z-10" >
44- < div className = "flex items-center mb-6 text-gray-800 dark:text-gray-100 font-bold text-lg" >
45- < SlidersHorizontal className = "mr-2" size = { 20 } /> Filters
40+ < div className = "min-h-screen bg-slate-50 dark:bg-slate-950 px-4 sm:px-6 lg:px-8 py-8" >
41+ { /* ── Page Header ──────────────────────────────────────────────── */ }
42+ < div className = "max-w-7xl mx-auto mb-8" >
43+ < div className = "flex items-start justify-between gap-4 flex-wrap" >
44+ < div >
45+ < div className = "flex items-center gap-2 mb-2" >
46+ < span className = "badge badge-primary" > QS 2026 Live</ span >
47+ < span className = "w-2 h-2 rounded-full bg-accent-500 animate-pulse" />
48+ < span className = "text-xs font-semibold text-accent-600 dark:text-accent-400" > Updated Daily</ span >
49+ </ div >
50+ < h1 className = "font-display font-extrabold text-3xl md:text-4xl text-slate-900 dark:text-white" >
51+ Compare < span className = "gradient-brand-text" > Universities</ span >
52+ </ h1 >
53+ < p className = "text-slate-500 dark:text-slate-400 mt-1 text-sm" >
54+ { loading ? "Loading..." : < > < span className = "font-bold text-slate-700 dark:text-slate-300" > { data . length } </ span > institutions match your criteria</ > }
55+ </ p >
56+ </ div >
57+ { hasFilters && (
58+ < button onClick = { clearFilters } className = "flex items-center gap-1.5 text-sm text-slate-500 hover:text-red-500 transition-colors font-semibold border border-slate-200 dark:border-slate-700 px-4 py-2 rounded-xl hover:border-red-200 dark:hover:border-red-900" >
59+ < X size = { 14 } /> Clear Filters
60+ </ button >
61+ ) }
4662 </ div >
63+ </ div >
4764
48- < div className = "space-y-6" >
49- < div className = "space-y-2" >
50- < label className = "text-sm font-semibold text-gray-500 uppercase flex items-center" > < GraduationCap size = { 14 } className = "mr-1" /> Course</ label >
51- < input
52- type = "text"
53- className = "w-full bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-gray-700 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-primary outline-none"
54- value = { course }
55- onChange = { ( e ) => setCourse ( e . target . value ) }
56- placeholder = "e.g. Computer Science"
57- />
58- </ div >
65+ < div className = "max-w-7xl mx-auto flex flex-col lg:flex-row gap-6" >
66+ { /* ── Sidebar Filters ───────────────────────────────────────── */ }
67+ < aside className = "w-full lg:w-72 shrink-0" >
68+ < div className = "bg-white dark:bg-slate-900 border border-slate-100 dark:border-slate-800 rounded-3xl p-6 shadow-card sticky top-24" >
69+ < div className = "flex items-center gap-2 mb-6" >
70+ < div className = "w-8 h-8 rounded-xl gradient-brand flex items-center justify-center" >
71+ < SlidersHorizontal size = { 15 } className = "text-white" />
72+ </ div >
73+ < span className = "font-display font-bold text-slate-900 dark:text-white" > Filters</ span >
74+ </ div >
5975
60- < div className = "space-y-2" >
61- < label className = "text-sm font-semibold text-gray-500 uppercase flex items-center" > < DollarSign size = { 14 } className = "mr-1" /> Max Tuition</ label >
62- < select
63- className = "w-full bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-gray-700 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-primary outline-none cursor-pointer"
64- value = { budget }
65- onChange = { ( e ) => setBudget ( e . target . value ) }
66- >
67- < option value = "" > Any Budget</ option >
68- < option value = "10L" > < 10 Lakhs INR/yr</ option >
69- < option value = "15L" > < 15 Lakhs INR/yr</ option >
70- < option value = "20L" > < 20 Lakhs INR/yr</ option >
71- < option value = "30L" > < 30 Lakhs INR/yr</ option >
72- < option value = "50L" > < 50 Lakhs INR/yr</ option >
73- < option value = "75L" > < 75 Lakhs INR/yr</ option >
74- < option value = "1Cr+" > 1 Cr+ (Premium)</ option >
75- </ select >
76- </ div >
76+ < div className = "space-y-5" >
77+ { /* Course */ }
78+ < div >
79+ < label className = "flex items-center gap-1.5 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-2" >
80+ < GraduationCap size = { 12 } /> Course / Discipline
81+ </ label >
82+ < input
83+ type = "text"
84+ className = "w-full bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-xl px-4 py-2.5 text-sm text-slate-800 dark:text-white focus:border-primary-400 focus:ring-2 focus:ring-primary-100 dark:focus:ring-primary-900 outline-none transition-all font-medium placeholder:text-slate-400"
85+ value = { course }
86+ onChange = { ( e ) => setCourse ( e . target . value ) }
87+ placeholder = "e.g. Computer Science"
88+ />
89+ </ div >
7790
78- < div className = "space-y-2" >
79- < label className = "text-sm font-semibold text-gray-500 uppercase flex items-center" > < MapPin size = { 14 } className = "mr-1" /> Location</ label >
80- < select
81- className = "w-full bg-gray-50 dark:bg-slate-800 border border-gray-200 dark:border-gray-700 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-primary outline-none cursor-pointer"
82- value = { location }
83- onChange = { ( e ) => setLocation ( e . target . value ) }
84- >
85- < option value = "Anywhere" > Global (All)</ option >
86- < option value = "India" > India</ option >
87- < option value = "USA" > United States</ option >
88- < option value = "UK" > United Kingdom</ option >
89- < option value = "Canada" > Canada</ option >
90- < option value = "Australia" > Australia</ option >
91- < option value = "Germany" > Germany</ option >
92- < option value = "Singapore" > Singapore</ option >
93- </ select >
94- </ div >
95- </ div >
96- </ aside >
91+ { /* Budget */ }
92+ < div >
93+ < label className = "flex items-center gap-1.5 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-2" >
94+ < DollarSign size = { 12 } /> Max Tuition / Year
95+ </ label >
96+ < select
97+ className = "w-full bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-xl px-4 py-2.5 text-sm text-slate-800 dark:text-white focus:border-primary-400 outline-none cursor-pointer font-medium"
98+ value = { budget }
99+ onChange = { ( e ) => setBudget ( e . target . value ) }
100+ >
101+ < option value = "" > Any Budget</ option >
102+ < option value = "10L" > < 10 Lakhs INR/yr</ option >
103+ < option value = "15L" > < 15 Lakhs INR/yr</ option >
104+ < option value = "20L" > < 20 Lakhs INR/yr</ option >
105+ < option value = "30L" > < 30 Lakhs INR/yr</ option >
106+ < option value = "50L" > < 50 Lakhs INR/yr</ option >
107+ < option value = "75L" > < 75 Lakhs INR/yr</ option >
108+ < option value = "1Cr+" > 1 Cr+ (Premium)</ option >
109+ </ select >
110+ </ div >
97111
98- < section className = "flex-1" >
99- < div className = "mb-6 flex justify-between items-end" >
100- < div >
101- < h2 className = "text-3xl font-extrabold text-transparent bg-clip-text bg-gradient-to-r from-gray-900 to-gray-600 dark:from-white dark:to-gray-400" >
102- University Rankings 2026
103- </ h2 >
104- < p className = "text-gray-500 mt-1 font-medium" > { data . length } institutions match your criteria</ p >
105- </ div >
106- </ div >
107-
108- { loading ? (
109- < div className = "flex space-x-2 justify-center items-center h-64" >
110- < div className = "w-3 h-3 bg-primary rounded-full animate-bounce" > </ div >
111- < div className = "w-3 h-3 bg-primary rounded-full animate-bounce delay-75" > </ div >
112- < div className = "w-3 h-3 bg-primary rounded-full animate-bounce delay-150" > </ div >
112+ { /* Location */ }
113+ < div >
114+ < label className = "flex items-center gap-1.5 text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-2" >
115+ < MapPin size = { 12 } /> Country / Region
116+ </ label >
117+ < select
118+ className = "w-full bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-xl px-4 py-2.5 text-sm text-slate-800 dark:text-white focus:border-primary-400 outline-none cursor-pointer font-medium"
119+ value = { location }
120+ onChange = { ( e ) => setLocation ( e . target . value ) }
121+ >
122+ < option value = "Anywhere" > Global (All)</ option >
123+ < option value = "India" > India</ option >
124+ < option value = "USA" > United States</ option >
125+ < option value = "UK" > United Kingdom</ option >
126+ < option value = "Canada" > Canada</ option >
127+ < option value = "Australia" > Australia</ option >
128+ < option value = "Germany" > Germany</ option >
129+ < option value = "Singapore" > Singapore</ option >
130+ </ select >
131+ </ div >
132+
133+ { /* Quick filter chips */ }
134+ < div >
135+ < label className = "text-xs font-bold text-slate-500 dark:text-slate-400 uppercase tracking-wider mb-2 block" > Popular Searches</ label >
136+ < div className = "flex flex-wrap gap-2" >
137+ { [ "MBA" , "CS" , "Data Science" , "AI" , "Finance" ] . map ( ( s ) => (
138+ < button key = { s } onClick = { ( ) => setCourse ( s ) }
139+ className = { `text-xs font-bold px-3 py-1.5 rounded-full transition-all ${ course === s ? "gradient-brand text-white" : "bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 hover:bg-primary-50 dark:hover:bg-primary-950 hover:text-primary" } ` } >
140+ { s }
141+ </ button >
142+ ) ) }
143+ </ div >
144+ </ div >
145+
146+ { /* AI suggestion hint */ }
147+ < div className = "bg-primary-50 dark:bg-primary-950/50 rounded-2xl p-4 border border-primary-100 dark:border-primary-900" >
148+ < div className = "flex items-center gap-2 mb-2" >
149+ < Sparkles size = { 14 } className = "text-primary" />
150+ < span className = "text-xs font-bold text-primary" > AI Counselor Tip</ span >
151+ </ div >
152+ < p className = "text-xs text-slate-600 dark:text-slate-400" >
153+ Not sure which country? Use the AI chatbot (bottom right) for personalized recommendations.
154+ </ p >
155+ </ div >
156+ </ div >
113157 </ div >
114- ) : (
115- < UniTable data = { data } />
116- ) }
117- </ section >
158+ </ aside >
159+
160+ { /* ── Results Table ─────────────────────────────────────────── */ }
161+ < section className = "flex-1 min-w-0" >
162+ { loading ? (
163+ < div className = "bg-white dark:bg-slate-900 rounded-3xl border border-slate-100 dark:border-slate-800 shadow-card p-10" >
164+ < div className = "space-y-4" >
165+ { [ ...Array ( 6 ) ] . map ( ( _ , i ) => (
166+ < div key = { i } className = "animate-pulse flex items-center gap-4 p-4 rounded-2xl bg-slate-50 dark:bg-slate-800" >
167+ < div className = "w-10 h-10 rounded-xl bg-slate-200 dark:bg-slate-700 shrink-0" />
168+ < div className = "flex-1 space-y-2" >
169+ < div className = "h-4 bg-slate-200 dark:bg-slate-700 rounded w-3/4" />
170+ < div className = "h-3 bg-slate-100 dark:bg-slate-700 rounded w-1/2" />
171+ </ div >
172+ < div className = "h-6 w-16 bg-slate-200 dark:bg-slate-700 rounded-full" />
173+ </ div >
174+ ) ) }
175+ </ div >
176+ </ div >
177+ ) : (
178+ < div className = "bg-white dark:bg-slate-900 rounded-3xl border border-slate-100 dark:border-slate-800 shadow-card overflow-hidden" >
179+ < UniTable data = { data } />
180+ </ div >
181+ ) }
182+ </ section >
183+ </ div >
118184 </ div >
119185 ) ;
120186}
121187
122188export default function ComparePage ( ) {
123189 return (
124- < Suspense fallback = { < div className = "text-center py-20 text-gray-500 animate-pulse" > Loading Comparison Interface...</ div > } >
190+ < Suspense fallback = {
191+ < div className = "flex items-center justify-center h-64 gap-3" >
192+ < div className = "w-3 h-3 bg-primary rounded-full animate-bounce" />
193+ < div className = "w-3 h-3 bg-primary rounded-full animate-bounce delay-100" />
194+ < div className = "w-3 h-3 bg-primary rounded-full animate-bounce delay-200" />
195+ </ div >
196+ } >
125197 < CompareContent />
126198 </ Suspense >
127199 ) ;
0 commit comments