Skip to content

Commit 0f6409e

Browse files
committed
feat: enhance Cohort component with improved layout, loading states, and custom scrollbar styles
1 parent 31569fc commit 0f6409e

File tree

2 files changed

+156
-65
lines changed

2 files changed

+156
-65
lines changed

src/components/landingPage/Cohort.jsx

Lines changed: 137 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useState, useEffect } from "react";
22
import { ArrowRight, Award, Users, BookOpen, Calendar, CheckCircle, AlertCircle } from "lucide-react";
33
import { MotionDiv, MotionSection, MotionH2, MotionP } from '../common/MotionWrapper';
4+
import { useNavigate } from "react-router-dom";
45

56
const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://api.openlearn.org.in';
67

@@ -30,45 +31,56 @@ const fetchCohortsStructure = async () => {
3031
}
3132
};
3233

33-
const LeagueCard = ({ league }) => {
34+
const LeagueCard = ({ league, accentColor }) => {
3435
const weeks = league.weeks || [];
36+
3537
return (
3638
<MotionDiv
37-
className="group relative rounded-2xl p-8 h-full bg-gradient-to-br from-white to-gray-50 border border-gray-200 shadow-lg hover:shadow-2xl"
39+
className="group relative rounded-2xl p-6 md:p-8 h-full bg-white border-2 border-gray-100 shadow-sm hover:shadow-lg transition-all duration-300"
3840
initial={{ opacity: 0, y: 50 }}
3941
whileInView={{ opacity: 1, y: 0 }}
4042
viewport={{ once: true, amount: 0.3 }}
4143
transition={{ duration: 0.6, ease: "easeOut" }}
4244
whileHover={{
43-
scale: 1.05,
44-
y: -10,
45+
y: -5,
46+
borderColor: '#FFDE59',
4547
transition: { duration: 0.3 }
4648
}}
4749
>
4850
{/* League Status Badge */}
49-
<div className="absolute -top-4 right-4 bg-gradient-to-r from-green-400 to-emerald-500 text-white px-4 py-2 rounded-full text-xs font-semibold shadow-md">
51+
<div className="absolute -top-3 right-4 bg-[#FFDE59] text-black px-4 py-2 rounded-full text-xs font-bold">
5052
<div className="flex items-center">
51-
<div className="w-2 h-2 bg-white rounded-full mr-2 animate-pulse"></div>
53+
<div className="w-2 h-2 bg-black rounded-full mr-2 animate-pulse"></div>
5254
Ongoing
5355
</div>
5456
</div>
5557

5658
{/* League Icon & Title */}
5759
<MotionDiv
58-
className="flex items-center mb-6"
60+
className="mb-6"
5961
initial={{ opacity: 0, x: -20 }}
6062
whileInView={{ opacity: 1, x: 0 }}
6163
viewport={{ once: true }}
6264
transition={{ duration: 0.5, delay: 0.2 }}
6365
>
64-
<h3 className="text-2xl font-bold transition-colors duration-300 text-gray-800 group-hover:text-gray-900">
65-
{league.name}
66-
</h3>
66+
<div className="flex items-center mb-3">
67+
<div
68+
className="w-12 h-12 rounded-xl flex items-center justify-center mr-4"
69+
style={{ backgroundColor: `${accentColor}15` }}
70+
>
71+
<BookOpen size={24} style={{ color: accentColor }} />
72+
</div>
73+
<div>
74+
<h3 className="text-xl md:text-2xl font-bold text-gray-900 group-hover:text-gray-800 transition-colors duration-300">
75+
{league.name}
76+
</h3>
77+
</div>
78+
</div>
6779
</MotionDiv>
6880

6981
{/* League Description */}
7082
<MotionP
71-
className="mb-6 leading-relaxed text-gray-600"
83+
className="mb-6 leading-relaxed text-gray-600 text-sm md:text-base"
7284
initial={{ opacity: 0 }}
7385
whileInView={{ opacity: 1 }}
7486
viewport={{ once: true }}
@@ -79,7 +91,7 @@ const LeagueCard = ({ league }) => {
7991

8092
{/* Week Count Badge */}
8193
<MotionDiv
82-
className="mb-6 inline-flex items-center px-4 py-2 rounded-lg text-sm font-medium bg-blue-50 text-blue-700 border border-blue-200"
94+
className="mb-6 inline-flex items-center px-4 py-2 rounded-lg text-sm font-medium bg-gray-50 text-gray-700 border border-gray-200"
8395
initial={{ opacity: 0, scale: 0.8 }}
8496
whileInView={{ opacity: 1, scale: 1 }}
8597
viewport={{ once: true }}
@@ -103,48 +115,54 @@ const LeagueCard = ({ league }) => {
103115
}}
104116
>
105117
<h4 className="text-sm font-semibold mb-3 text-gray-700">
106-
Whats going on:
118+
What's Going to be Covered:
107119
</h4>
108-
<div className="space-y-2 max-h-48 overflow-y-auto">
120+
<div className="space-y-2 max-h-48 overflow-y-auto custom-scrollbar">
109121
{weeks
110122
.sort((a, b) => a.order - b.order)
123+
.slice(0, 3) // Show only first 5 weeks to prevent overflow
111124
.map((week, index) => (
112125
<MotionDiv
113126
key={week.id}
114-
className="flex items-start text-sm group/week text-gray-600"
127+
className="flex items-start text-sm group/week text-gray-600 hover:text-gray-800 transition-colors duration-200"
115128
initial={{ opacity: 0, x: -20 }}
116129
whileInView={{ opacity: 1, x: 0 }}
117130
viewport={{ once: true }}
118131
transition={{ duration: 0.3, delay: 0.1 * index }}
119-
whileHover={{ x: 5 }}
132+
whileHover={{ x: 3 }}
120133
>
121-
<div className="w-2 h-2 rounded-full mt-2 mr-3 flex-shrink-0 bg-blue-400" />
134+
<CheckCircle size={14} className="mt-1 mr-3 flex-shrink-0 text-[#FFDE59]" />
122135
<div className="flex-1">
123-
<span className="font-medium text-gray-700">
136+
<span className="font-medium">
124137
{week.name}
125138
</span>
126139
</div>
127140
</MotionDiv>
128141
))}
142+
{weeks.length > 3 && (
143+
<div className="text-xs text-gray-500 italic">
144+
+{weeks.length - 3} more weeks...
145+
</div>
146+
)}
129147
</div>
130148
</MotionDiv>
131149
)}
132150

133151
{/* League Stats */}
134152
<MotionDiv
135-
className="flex items-center justify-between pt-4 border-t border-gray-200"
153+
className="flex items-center justify-between pt-4 border-t border-gray-100"
136154
initial={{ opacity: 0, y: 20 }}
137155
whileInView={{ opacity: 1, y: 0 }}
138156
viewport={{ once: true }}
139157
transition={{ duration: 0.5, delay: 0.6 }}
140158
>
141159
<div className="flex items-center text-sm">
142160
<Users size={16} className="mr-2 text-gray-500" />
143-
<span className="text-gray-600">Join League</span>
161+
<span className="text-gray-600 font-medium">Community</span>
144162
</div>
145163
<div className="flex items-center text-sm">
146-
<Award size={16} className="mr-2 text-blue-500" />
147-
<span className="text-blue-600">Certificate</span>
164+
<Award size={16} className="mr-2 text-[#FFDE59]" />
165+
<span className="text-gray-700 font-medium">Certificate</span>
148166
</div>
149167
</MotionDiv>
150168
</MotionDiv>
@@ -155,6 +173,7 @@ const Cohort = () => {
155173
const [cohortsData, setCohortsData] = useState(null);
156174
const [loading, setLoading] = useState(true);
157175
const [error, setError] = useState(null);
176+
const navigate = useNavigate();
158177

159178
useEffect(() => {
160179
console.log('🔄 Cohort component mounted - starting data fetch...');
@@ -195,14 +214,17 @@ const Cohort = () => {
195214
return (
196215
<MotionSection
197216
id="cohort"
198-
className="py-20 pb-24 bg-gradient-to-br from-slate-50 via-white to-blue-50"
217+
className="py-16 md:py-20 lg:py-24 bg-white"
199218
initial={{ opacity: 0 }}
200219
animate={{ opacity: 1 }}
201220
>
202-
<div className="container mx-auto px-6 text-center">
203-
<div className="flex items-center justify-center space-x-2">
204-
<div className="w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin"></div>
205-
<span className="text-gray-600">Loading learning paths...</span>
221+
<div className="container mx-auto px-4 md:px-6 text-center">
222+
<div className="max-w-md mx-auto">
223+
<div className="flex items-center justify-center mb-4">
224+
<div className="w-12 h-12 border-4 border-[#FFDE59] border-t-transparent rounded-full animate-spin"></div>
225+
</div>
226+
<h3 className="text-xl font-semibold text-gray-800 mb-2">Loading Learning Paths</h3>
227+
<p className="text-gray-600">Fetching the latest learning opportunities for you...</p>
206228
</div>
207229
</div>
208230
</MotionSection>
@@ -215,21 +237,26 @@ const Cohort = () => {
215237
return (
216238
<MotionSection
217239
id="cohort"
218-
className="py-20 pb-24 bg-gradient-to-br from-slate-50 via-white to-blue-50"
240+
className="py-16 md:py-20 lg:py-24 bg-white"
219241
initial={{ opacity: 0 }}
220242
animate={{ opacity: 1 }}
221243
>
222-
<div className="container mx-auto px-6 text-center">
223-
<div className="flex items-center justify-center space-x-2 text-red-600">
224-
<AlertCircle size={24} />
225-
<span>Failed to load learning paths: {error}</span>
226-
</div>
227-
<div className="mt-4">
244+
<div className="container mx-auto px-4 md:px-6 text-center">
245+
<div className="max-w-md mx-auto bg-red-50 border border-red-200 rounded-2xl p-8">
246+
<div className="flex items-center justify-center mb-4">
247+
<div className="w-16 h-16 bg-red-100 rounded-full flex items-center justify-center">
248+
<AlertCircle size={32} className="text-red-600" />
249+
</div>
250+
</div>
251+
<h3 className="text-xl font-semibold text-red-800 mb-2">Oops! Something went wrong</h3>
252+
<p className="text-red-600 mb-6">
253+
We couldn't load the learning paths. Please try again.
254+
</p>
228255
<button
229256
onClick={() => window.location.reload()}
230-
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
257+
className="bg-red-600 hover:bg-red-700 text-white font-semibold py-3 px-6 rounded-xl transition-colors duration-300"
231258
>
232-
Retry
259+
Try Again
233260
</button>
234261
</div>
235262
</div>
@@ -246,12 +273,22 @@ const Cohort = () => {
246273
return (
247274
<MotionSection
248275
id="cohort"
249-
className="py-20 pb-24 bg-gradient-to-br from-slate-50 via-white to-blue-50"
276+
className="py-16 md:py-20 lg:py-24 bg-white"
250277
initial={{ opacity: 0 }}
251278
animate={{ opacity: 1 }}
252279
>
253-
<div className="container mx-auto px-6 text-center">
254-
<div className="text-gray-600">No active cohorts available at the moment.</div>
280+
<div className="container mx-auto px-4 md:px-6 text-center">
281+
<div className="max-w-md mx-auto bg-gray-50 border border-gray-200 rounded-2xl p-8">
282+
<div className="flex items-center justify-center mb-4">
283+
<div className="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center">
284+
<BookOpen size={32} className="text-gray-400" />
285+
</div>
286+
</div>
287+
<h3 className="text-xl font-semibold text-gray-800 mb-2">No Active Cohorts</h3>
288+
<p className="text-gray-600">
289+
We're preparing exciting learning opportunities. Check back soon!
290+
</p>
291+
</div>
255292
</div>
256293
</MotionSection>
257294
);
@@ -277,7 +314,7 @@ const Cohort = () => {
277314
return (
278315
<MotionSection
279316
id="cohort"
280-
className="py-20 pb-24 bg-gradient-to-br from-slate-50 via-white to-blue-50 relative overflow-hidden"
317+
className="py-16 md:py-20 lg:py-24 bg-white relative overflow-hidden"
281318
initial="hidden"
282319
whileInView="visible"
283320
viewport={{ once: true, amount: 0.1 }}
@@ -292,16 +329,26 @@ const Cohort = () => {
292329
}
293330
}}
294331
>
295-
{/* Background decorations */}
296-
<div className="absolute inset-0 overflow-hidden">
297-
<div className="absolute -top-40 -right-40 w-80 h-80 bg-gradient-to-br from-blue-100 to-purple-100 rounded-full opacity-50 blur-3xl"></div>
298-
<div className="absolute -bottom-40 -left-40 w-80 h-80 bg-gradient-to-br from-green-100 to-blue-100 rounded-full opacity-50 blur-3xl"></div>
332+
{/* Background Pattern */}
333+
<div className="absolute inset-0 opacity-[0.02]">
334+
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
335+
<pattern id="grid" x="0" y="0" width="40" height="40" patternUnits="userSpaceOnUse">
336+
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="#000000" strokeWidth="1"/>
337+
</pattern>
338+
<rect x="0" y="0" width="100%" height="100%" fill="url(#grid)" />
339+
</svg>
340+
</div>
341+
342+
{/* Decorative Elements */}
343+
<div className="absolute inset-0 overflow-hidden pointer-events-none">
344+
<div className="absolute -top-40 -right-40 w-80 h-80 bg-[#FFDE59] rounded-full opacity-5 blur-3xl"></div>
345+
<div className="absolute -bottom-40 -left-40 w-80 h-80 bg-gray-900 rounded-full opacity-5 blur-3xl"></div>
299346
</div>
300347

301-
<div className="container mx-auto px-6 relative z-10">
348+
<div className="container mx-auto px-4 md:px-6 relative z-10">
302349
{/* Header Section */}
303350
<MotionDiv
304-
className="text-center mb-20 max-w-4xl mx-auto"
351+
className="text-center mb-16 md:mb-20 max-w-4xl mx-auto"
305352
variants={{
306353
hidden: { opacity: 1, y: 30 },
307354
visible: {
@@ -315,30 +362,30 @@ const Cohort = () => {
315362
}}
316363
>
317364
<MotionH2
318-
className="text-5xl font-bold mb-6 bg-gradient-to-r from-gray-800 via-gray-900 to-gray-800 bg-clip-text text-transparent"
365+
className="text-3xl md:text-4xl lg:text-5xl font-bold mb-6 text-gray-900"
319366
>
320367
{cohort.name} – Learning Leagues
321368
</MotionH2>
322369

323370
<MotionP
324-
className="text-xl text-gray-600 mb-8 leading-relaxed"
371+
className="text-lg md:text-xl text-gray-600 mb-8 leading-relaxed max-w-3xl mx-auto"
325372
>
326373
{cohort.description}
327374
</MotionP>
328375

329-
{/* Stats */}
330-
<MotionDiv className="flex items-center justify-center flex-wrap gap-4 text-sm">
331-
<div className="flex items-center space-x-2 bg-white px-4 py-2 rounded-full shadow-md">
332-
<BookOpen size={16} className="text-blue-500" />
333-
<span className="font-medium">{leagues.length} League{leagues.length !== 1 ? 's' : ''}</span>
376+
{/* Enhanced Stats */}
377+
<MotionDiv className="flex items-center justify-center flex-wrap gap-4 md:gap-6">
378+
<div className="flex cursor-pointer items-center space-x-2 bg-gray-50 hover:bg-[#FFDE59] transition-colors duration-300 px-4 md:px-6 py-3 rounded-full border border-gray-200 group">
379+
<BookOpen size={18} className="text-gray-700 group-hover:text-black transition-colors duration-300" />
380+
<span className="font-semibold text-gray-800 group-hover:text-black transition-colors duration-300">
381+
{leagues.length} Learning League{leagues.length !== 1 ? 's' : ''}
382+
</span>
334383
</div>
335-
<div className="flex items-center space-x-2 bg-white px-4 py-2 rounded-full shadow-md">
336-
<Calendar size={16} className="text-green-500" />
337-
<span className="font-medium">{totalWeeks} Total Weeks</span>
338-
</div>
339-
<div className="flex items-center space-x-2 bg-white px-4 py-2 rounded-full shadow-md">
340-
<CheckCircle size={16} className="text-purple-500" />
341-
<span className="font-medium">Certificates Available</span>
384+
<div className="flex cursor-pointer items-center space-x-2 bg-gray-50 hover:bg-[#FFDE59] transition-colors duration-300 px-4 md:px-6 py-3 rounded-full border border-gray-200 group">
385+
<Award size={18} className="text-gray-700 group-hover:text-black transition-colors duration-300" />
386+
<span className="font-semibold text-gray-800 group-hover:text-black transition-colors duration-300">
387+
Certificates Available
388+
</span>
342389
</div>
343390
</MotionDiv>
344391
</MotionDiv>
@@ -347,11 +394,11 @@ const Cohort = () => {
347394
<MotionDiv className="relative max-w-7xl mx-auto">
348395
{/* Leagues Grid */}
349396
<MotionDiv
350-
className={`grid gap-12 ${
397+
className={`grid gap-8 md:gap-12 ${
351398
leagues.length === 1
352399
? 'max-w-2xl mx-auto'
353400
: leagues.length === 2
354-
? 'lg:grid-cols-2 lg:gap-20'
401+
? 'lg:grid-cols-2 lg:gap-16'
355402
: 'lg:grid-cols-2 xl:grid-cols-3'
356403
}`}
357404
>
@@ -361,8 +408,8 @@ const Cohort = () => {
361408
return (
362409
<MotionDiv
363410
key={league.id}
364-
initial={{ opacity: 0, x: index % 2 === 0 ? -50 : 50 }}
365-
whileInView={{ opacity: 1, x: 0 }}
411+
initial={{ opacity: 0, y: 50 }}
412+
whileInView={{ opacity: 1, y: 0 }}
366413
viewport={{ once: true }}
367414
transition={{ duration: 0.6, delay: index * 0.2 }}
368415
>
@@ -375,6 +422,32 @@ const Cohort = () => {
375422
})}
376423
</MotionDiv>
377424
</MotionDiv>
425+
426+
{/* Bottom CTA Section */}
427+
<MotionDiv
428+
className="text-center mt-16 md:mt-20"
429+
initial={{ opacity: 0, y: 30 }}
430+
whileInView={{ opacity: 1, y: 0 }}
431+
viewport={{ once: true }}
432+
transition={{ duration: 0.6, delay: 0.5 }}
433+
>
434+
<div className="bg-gray-50 rounded-2xl p-8 md:p-12 border border-gray-200 max-w-4xl mx-auto">
435+
<h3 className="text-2xl md:text-3xl font-bold text-gray-900 mb-4">
436+
Ready to Start Your Learning Journey?
437+
</h3>
438+
<p className="text-gray-600 mb-6 text-lg">
439+
Join thousands of learners and start building skills that matter.
440+
</p>
441+
<button
442+
className="bg-[#FFDE59] hover:bg-yellow-400 text-black font-bold py-4 px-8 rounded-xl transition-all duration-300 transform hover:scale-105"
443+
onClick={() => {
444+
navigate('/signin');
445+
}}
446+
>
447+
Get Started Today
448+
</button>
449+
</div>
450+
</MotionDiv>
378451
</div>
379452
</MotionSection>
380453
);

0 commit comments

Comments
 (0)