muhammad naveed commited on
Commit
1291157
·
verified ·
1 Parent(s): 2706b44

Upload folder using huggingface_hub

Browse files
Dockerfile ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:18-alpine
2
+
3
+ WORKDIR /app
4
+
5
+ # Copy package files
6
+ COPY package*.json ./
7
+
8
+ # Install dependencies
9
+ RUN npm install
10
+
11
+ # Copy application code
12
+ COPY . .
13
+
14
+ # Set the API URL to the Hugging Face deployed API
15
+ ENV NEXT_PUBLIC_API_URL=https://naveed247365-learnflow-api.hf.space
16
+
17
+ # Build the application
18
+ RUN npm run build
19
+
20
+ # Expose port
21
+ EXPOSE 3000
22
+
23
+ # Start the application
24
+ CMD ["npm", "start"]
README.md CHANGED
@@ -1,10 +1,33 @@
1
  ---
2
- title: Learnflow
3
- emoji: 💻
4
  colorFrom: green
5
- colorTo: indigo
6
  sdk: docker
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: LearnFlow
3
+ emoji: 🎓
4
  colorFrom: green
5
+ colorTo: blue
6
  sdk: docker
7
  pinned: false
8
+ license: mit
9
+ app_port: 3000
10
  ---
11
 
12
+ # LearnFlow - AI-Powered Python Learning Platform
13
+
14
+ An interactive Python learning platform with AI tutors, code execution, and progress tracking.
15
+
16
+ ## Features
17
+
18
+ - **AI Python Tutor** - Get instant help with Python questions
19
+ - **Interactive Code Editor** - Write and run Python code
20
+ - **Quizzes** - Test your knowledge
21
+ - **Progress Tracking** - Track your learning journey
22
+ - **Learning Resources** - Guides, cheatsheets, videos
23
+
24
+ ## Tech Stack
25
+
26
+ - Next.js 14
27
+ - Tailwind CSS
28
+ - TypeScript
29
+ - Monaco Editor
30
+
31
+ ## Live Demo
32
+
33
+ Try it out! Register an account and start learning Python.
app/about/page.tsx ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import Link from 'next/link';
4
+
5
+ export default function AboutPage() {
6
+ const team = [
7
+ { name: 'Dr. Sarah Chen', role: 'Founder & CEO', image: '👩‍💼', bio: 'Former Google engineer with 15 years in EdTech' },
8
+ { name: 'Muhammad Ali', role: 'Lead AI Engineer', image: '👨‍💻', bio: 'PhD in Machine Learning, Stanford University' },
9
+ { name: 'Emily Rodriguez', role: 'Head of Curriculum', image: '👩‍🏫', bio: '10 years teaching Python at MIT' },
10
+ { name: 'James Wilson', role: 'CTO', image: '👨‍🔬', bio: 'Built scalable systems at AWS and Netflix' },
11
+ ];
12
+
13
+ const values = [
14
+ { icon: '🎯', title: 'Personalized Learning', description: 'AI adapts to your pace and learning style' },
15
+ { icon: '🤝', title: 'Supportive Community', description: 'Learn alongside thousands of motivated students' },
16
+ { icon: '💡', title: 'Practical Skills', description: 'Build real projects, not just theory' },
17
+ { icon: '🚀', title: 'Career Growth', description: 'Skills that employers actually want' },
18
+ ];
19
+
20
+ const milestones = [
21
+ { year: '2022', event: 'LearnFlow founded with a mission to democratize coding education' },
22
+ { year: '2023', event: 'Launched AI tutoring system, reached 10,000 students' },
23
+ { year: '2024', event: 'Expanded to 50+ countries, 100,000+ students enrolled' },
24
+ { year: '2025', event: 'Introduced advanced debugging agent and teacher dashboard' },
25
+ ];
26
+
27
+ return (
28
+ <div className="min-h-screen bg-gradient-to-b from-cream-50 to-white">
29
+ {/* Header */}
30
+ <header className="bg-white/80 backdrop-blur-md border-b border-warmgray-100 sticky top-0 z-50">
31
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
32
+ <div className="flex items-center justify-between h-16">
33
+ <Link href="/" className="flex items-center space-x-3">
34
+ <div className="w-10 h-10 bg-gradient-to-br from-teal-500 to-teal-600 rounded-xl flex items-center justify-center shadow-soft">
35
+ <span className="text-white font-bold text-lg">L</span>
36
+ </div>
37
+ <span className="text-xl font-bold text-warmgray-900">LearnFlow</span>
38
+ </Link>
39
+
40
+ <nav className="hidden md:flex items-center space-x-1">
41
+ {[
42
+ { name: 'Home', href: '/' },
43
+ { name: 'Courses', href: '/courses' },
44
+ { name: 'About', href: '/about' },
45
+ { name: 'Resources', href: '/resources' },
46
+ { name: 'Contact', href: '/contact' },
47
+ ].map((item) => (
48
+ <Link
49
+ key={item.name}
50
+ href={item.href}
51
+ className={`px-4 py-2 rounded-full text-sm font-medium transition-all duration-200 ${
52
+ item.name === 'About'
53
+ ? 'bg-teal-50 text-teal-700'
54
+ : 'text-warmgray-600 hover:text-teal-700 hover:bg-teal-50'
55
+ }`}
56
+ >
57
+ {item.name}
58
+ </Link>
59
+ ))}
60
+ </nav>
61
+
62
+ <div className="flex items-center space-x-3">
63
+ <Link href="/register" className="text-warmgray-700 hover:text-teal-700 font-medium text-sm">
64
+ Sign Up
65
+ </Link>
66
+ <Link href="/" className="bg-teal-600 text-white px-5 py-2.5 rounded-full hover:bg-teal-700 transition-all font-medium text-sm">
67
+ Login
68
+ </Link>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </header>
73
+
74
+ {/* Hero Section */}
75
+ <section className="py-20 px-4">
76
+ <div className="max-w-4xl mx-auto text-center">
77
+ <h1 className="text-4xl md:text-5xl font-bold text-warmgray-900 mb-6">
78
+ About <span className="text-teal-600">LearnFlow</span>
79
+ </h1>
80
+ <p className="text-xl text-warmgray-600 leading-relaxed">
81
+ We're on a mission to make Python programming accessible to everyone through
82
+ AI-powered personalized learning experiences.
83
+ </p>
84
+ </div>
85
+ </section>
86
+
87
+ {/* Our Story */}
88
+ <section className="py-16 px-4 bg-white">
89
+ <div className="max-w-6xl mx-auto">
90
+ <div className="grid md:grid-cols-2 gap-12 items-center">
91
+ <div>
92
+ <h2 className="text-3xl font-bold text-warmgray-900 mb-6">Our Story</h2>
93
+ <p className="text-warmgray-600 mb-4">
94
+ LearnFlow was born from a simple observation: traditional coding education doesn't work for everyone.
95
+ Students learn at different paces, have different backgrounds, and need different types of support.
96
+ </p>
97
+ <p className="text-warmgray-600 mb-4">
98
+ We built LearnFlow to solve this problem. Our AI tutors adapt to each student's learning style,
99
+ providing personalized explanations, debugging help, and practice exercises.
100
+ </p>
101
+ <p className="text-warmgray-600">
102
+ Today, we're proud to help over 100,000 students worldwide learn Python effectively,
103
+ with teacher dashboards that help educators identify and support struggling students.
104
+ </p>
105
+ </div>
106
+ <div className="bg-gradient-to-br from-teal-500 to-sage-500 rounded-3xl p-8 text-white">
107
+ <div className="grid grid-cols-2 gap-6">
108
+ <div className="text-center">
109
+ <div className="text-4xl font-bold">100K+</div>
110
+ <div className="text-teal-100">Students</div>
111
+ </div>
112
+ <div className="text-center">
113
+ <div className="text-4xl font-bold">50+</div>
114
+ <div className="text-teal-100">Countries</div>
115
+ </div>
116
+ <div className="text-center">
117
+ <div className="text-4xl font-bold">95%</div>
118
+ <div className="text-teal-100">Completion Rate</div>
119
+ </div>
120
+ <div className="text-center">
121
+ <div className="text-4xl font-bold">4.8</div>
122
+ <div className="text-teal-100">Avg Rating</div>
123
+ </div>
124
+ </div>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ </section>
129
+
130
+ {/* Our Values */}
131
+ <section className="py-16 px-4">
132
+ <div className="max-w-6xl mx-auto">
133
+ <h2 className="text-3xl font-bold text-warmgray-900 text-center mb-12">Our Values</h2>
134
+ <div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
135
+ {values.map((value, index) => (
136
+ <div key={index} className="bg-white rounded-2xl p-6 shadow-soft hover:shadow-soft-lg transition-shadow">
137
+ <div className="text-4xl mb-4">{value.icon}</div>
138
+ <h3 className="font-semibold text-warmgray-900 mb-2">{value.title}</h3>
139
+ <p className="text-warmgray-600 text-sm">{value.description}</p>
140
+ </div>
141
+ ))}
142
+ </div>
143
+ </div>
144
+ </section>
145
+
146
+ {/* Timeline */}
147
+ <section className="py-16 px-4 bg-white">
148
+ <div className="max-w-4xl mx-auto">
149
+ <h2 className="text-3xl font-bold text-warmgray-900 text-center mb-12">Our Journey</h2>
150
+ <div className="space-y-8">
151
+ {milestones.map((milestone, index) => (
152
+ <div key={index} className="flex gap-6">
153
+ <div className="flex-shrink-0 w-20 text-right">
154
+ <span className="text-teal-600 font-bold">{milestone.year}</span>
155
+ </div>
156
+ <div className="flex-shrink-0 w-4 h-4 mt-1 bg-teal-500 rounded-full relative">
157
+ {index < milestones.length - 1 && (
158
+ <div className="absolute top-4 left-1/2 w-0.5 h-16 bg-teal-200 -translate-x-1/2" />
159
+ )}
160
+ </div>
161
+ <div className="flex-1 pb-8">
162
+ <p className="text-warmgray-700">{milestone.event}</p>
163
+ </div>
164
+ </div>
165
+ ))}
166
+ </div>
167
+ </div>
168
+ </section>
169
+
170
+ {/* Team */}
171
+ <section className="py-16 px-4">
172
+ <div className="max-w-6xl mx-auto">
173
+ <h2 className="text-3xl font-bold text-warmgray-900 text-center mb-12">Meet Our Team</h2>
174
+ <div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6">
175
+ {team.map((member, index) => (
176
+ <div key={index} className="bg-white rounded-2xl p-6 shadow-soft text-center hover:shadow-soft-lg transition-shadow">
177
+ <div className="text-6xl mb-4">{member.image}</div>
178
+ <h3 className="font-semibold text-warmgray-900">{member.name}</h3>
179
+ <p className="text-teal-600 text-sm mb-2">{member.role}</p>
180
+ <p className="text-warmgray-500 text-sm">{member.bio}</p>
181
+ </div>
182
+ ))}
183
+ </div>
184
+ </div>
185
+ </section>
186
+
187
+ {/* CTA */}
188
+ <section className="py-16 px-4 bg-gradient-to-r from-teal-600 to-teal-700">
189
+ <div className="max-w-4xl mx-auto text-center text-white">
190
+ <h2 className="text-3xl font-bold mb-4">Join Our Learning Community</h2>
191
+ <p className="text-teal-100 mb-8">Start your Python journey today with AI-powered personalized learning.</p>
192
+ <Link
193
+ href="/register"
194
+ className="inline-block bg-white text-teal-700 px-8 py-3 rounded-full font-semibold hover:bg-cream-50 transition-colors shadow-lg"
195
+ >
196
+ Get Started Free
197
+ </Link>
198
+ </div>
199
+ </section>
200
+ </div>
201
+ );
202
+ }
app/contact/page.tsx ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import Link from 'next/link';
4
+ import { useState } from 'react';
5
+
6
+ export default function ContactPage() {
7
+ const [formData, setFormData] = useState({
8
+ name: '',
9
+ email: '',
10
+ subject: '',
11
+ message: '',
12
+ });
13
+ const [isSubmitting, setIsSubmitting] = useState(false);
14
+ const [submitted, setSubmitted] = useState(false);
15
+
16
+ const handleSubmit = async (e: React.FormEvent) => {
17
+ e.preventDefault();
18
+ setIsSubmitting(true);
19
+
20
+ // Simulate form submission
21
+ await new Promise(resolve => setTimeout(resolve, 1500));
22
+
23
+ setIsSubmitting(false);
24
+ setSubmitted(true);
25
+ setFormData({ name: '', email: '', subject: '', message: '' });
26
+ };
27
+
28
+ const contactInfo = [
29
+ { icon: '📧', label: 'Email', value: 'support@learnflow.com', href: 'mailto:support@learnflow.com' },
30
+ { icon: '📞', label: 'Phone', value: '+1 (555) 123-4567', href: 'tel:+15551234567' },
31
+ { icon: '📍', label: 'Address', value: '123 Learning Street, San Francisco, CA 94102', href: '#' },
32
+ ];
33
+
34
+ const faqs = [
35
+ { q: 'How do I reset my password?', a: 'Click "Forgot Password" on the login page and follow the instructions.' },
36
+ { q: 'Can I get a refund?', a: 'Yes, we offer a 30-day money-back guarantee on all courses.' },
37
+ { q: 'How do I contact my instructor?', a: 'Use the chat feature in your course dashboard to message your instructor.' },
38
+ { q: 'Is there a mobile app?', a: 'Our mobile app is coming soon! Currently, our website works great on mobile browsers.' },
39
+ ];
40
+
41
+ return (
42
+ <div className="min-h-screen bg-gradient-to-b from-cream-50 to-white">
43
+ {/* Header */}
44
+ <header className="bg-white/80 backdrop-blur-md border-b border-warmgray-100 sticky top-0 z-50">
45
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
46
+ <div className="flex items-center justify-between h-16">
47
+ <Link href="/" className="flex items-center space-x-3">
48
+ <div className="w-10 h-10 bg-gradient-to-br from-teal-500 to-teal-600 rounded-xl flex items-center justify-center shadow-soft">
49
+ <span className="text-white font-bold text-lg">L</span>
50
+ </div>
51
+ <span className="text-xl font-bold text-warmgray-900">LearnFlow</span>
52
+ </Link>
53
+
54
+ <nav className="hidden md:flex items-center space-x-1">
55
+ {[
56
+ { name: 'Home', href: '/' },
57
+ { name: 'Courses', href: '/courses' },
58
+ { name: 'About', href: '/about' },
59
+ { name: 'Resources', href: '/resources' },
60
+ { name: 'Contact', href: '/contact' },
61
+ ].map((item) => (
62
+ <Link
63
+ key={item.name}
64
+ href={item.href}
65
+ className={`px-4 py-2 rounded-full text-sm font-medium transition-all duration-200 ${
66
+ item.name === 'Contact'
67
+ ? 'bg-teal-50 text-teal-700'
68
+ : 'text-warmgray-600 hover:text-teal-700 hover:bg-teal-50'
69
+ }`}
70
+ >
71
+ {item.name}
72
+ </Link>
73
+ ))}
74
+ </nav>
75
+
76
+ <div className="flex items-center space-x-3">
77
+ <Link href="/register" className="text-warmgray-700 hover:text-teal-700 font-medium text-sm">
78
+ Sign Up
79
+ </Link>
80
+ <Link href="/" className="bg-teal-600 text-white px-5 py-2.5 rounded-full hover:bg-teal-700 transition-all font-medium text-sm">
81
+ Login
82
+ </Link>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ </header>
87
+
88
+ {/* Hero Section */}
89
+ <section className="py-16 px-4">
90
+ <div className="max-w-4xl mx-auto text-center">
91
+ <h1 className="text-4xl md:text-5xl font-bold text-warmgray-900 mb-4">
92
+ Get in <span className="text-teal-600">Touch</span>
93
+ </h1>
94
+ <p className="text-lg text-warmgray-600">
95
+ Have questions? We'd love to hear from you. Send us a message and we'll respond as soon as possible.
96
+ </p>
97
+ </div>
98
+ </section>
99
+
100
+ {/* Contact Info Cards */}
101
+ <section className="px-4 pb-12">
102
+ <div className="max-w-4xl mx-auto">
103
+ <div className="grid md:grid-cols-3 gap-6">
104
+ {contactInfo.map((info, index) => (
105
+ <a
106
+ key={index}
107
+ href={info.href}
108
+ className="bg-white rounded-2xl p-6 shadow-soft hover:shadow-soft-lg transition-all text-center group"
109
+ >
110
+ <div className="text-4xl mb-3">{info.icon}</div>
111
+ <div className="text-sm text-warmgray-500 mb-1">{info.label}</div>
112
+ <div className="font-medium text-warmgray-900 group-hover:text-teal-600 transition-colors">
113
+ {info.value}
114
+ </div>
115
+ </a>
116
+ ))}
117
+ </div>
118
+ </div>
119
+ </section>
120
+
121
+ {/* Contact Form & FAQs */}
122
+ <section className="px-4 pb-20">
123
+ <div className="max-w-6xl mx-auto">
124
+ <div className="grid lg:grid-cols-2 gap-12">
125
+ {/* Contact Form */}
126
+ <div className="bg-white rounded-3xl p-8 shadow-soft">
127
+ <h2 className="text-2xl font-bold text-warmgray-900 mb-6">Send us a Message</h2>
128
+
129
+ {submitted ? (
130
+ <div className="text-center py-12">
131
+ <div className="text-6xl mb-4">✅</div>
132
+ <h3 className="text-xl font-semibold text-warmgray-900 mb-2">Message Sent!</h3>
133
+ <p className="text-warmgray-600 mb-6">We'll get back to you within 24 hours.</p>
134
+ <button
135
+ onClick={() => setSubmitted(false)}
136
+ className="text-teal-600 font-medium hover:text-teal-700"
137
+ >
138
+ Send another message
139
+ </button>
140
+ </div>
141
+ ) : (
142
+ <form onSubmit={handleSubmit} className="space-y-5">
143
+ <div>
144
+ <label className="block text-sm font-medium text-warmgray-700 mb-2">Your Name</label>
145
+ <input
146
+ type="text"
147
+ required
148
+ value={formData.name}
149
+ onChange={(e) => setFormData({ ...formData, name: e.target.value })}
150
+ className="w-full px-4 py-3 rounded-xl border border-warmgray-200 focus:border-teal-500 focus:ring-2 focus:ring-teal-500/20 outline-none transition-all"
151
+ placeholder="John Doe"
152
+ />
153
+ </div>
154
+ <div>
155
+ <label className="block text-sm font-medium text-warmgray-700 mb-2">Email Address</label>
156
+ <input
157
+ type="email"
158
+ required
159
+ value={formData.email}
160
+ onChange={(e) => setFormData({ ...formData, email: e.target.value })}
161
+ className="w-full px-4 py-3 rounded-xl border border-warmgray-200 focus:border-teal-500 focus:ring-2 focus:ring-teal-500/20 outline-none transition-all"
162
+ placeholder="john@example.com"
163
+ />
164
+ </div>
165
+ <div>
166
+ <label className="block text-sm font-medium text-warmgray-700 mb-2">Subject</label>
167
+ <select
168
+ required
169
+ value={formData.subject}
170
+ onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
171
+ className="w-full px-4 py-3 rounded-xl border border-warmgray-200 focus:border-teal-500 focus:ring-2 focus:ring-teal-500/20 outline-none transition-all"
172
+ >
173
+ <option value="">Select a subject</option>
174
+ <option value="general">General Inquiry</option>
175
+ <option value="support">Technical Support</option>
176
+ <option value="billing">Billing Question</option>
177
+ <option value="partnership">Partnership Opportunity</option>
178
+ <option value="feedback">Feedback</option>
179
+ </select>
180
+ </div>
181
+ <div>
182
+ <label className="block text-sm font-medium text-warmgray-700 mb-2">Message</label>
183
+ <textarea
184
+ required
185
+ rows={5}
186
+ value={formData.message}
187
+ onChange={(e) => setFormData({ ...formData, message: e.target.value })}
188
+ className="w-full px-4 py-3 rounded-xl border border-warmgray-200 focus:border-teal-500 focus:ring-2 focus:ring-teal-500/20 outline-none transition-all resize-none"
189
+ placeholder="How can we help you?"
190
+ />
191
+ </div>
192
+ <button
193
+ type="submit"
194
+ disabled={isSubmitting}
195
+ className="w-full bg-teal-600 text-white py-3 rounded-xl font-semibold hover:bg-teal-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
196
+ >
197
+ {isSubmitting ? (
198
+ <>
199
+ <svg className="animate-spin h-5 w-5" viewBox="0 0 24 24">
200
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
201
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
202
+ </svg>
203
+ Sending...
204
+ </>
205
+ ) : (
206
+ 'Send Message'
207
+ )}
208
+ </button>
209
+ </form>
210
+ )}
211
+ </div>
212
+
213
+ {/* FAQs */}
214
+ <div>
215
+ <h2 className="text-2xl font-bold text-warmgray-900 mb-6">Frequently Asked Questions</h2>
216
+ <div className="space-y-4">
217
+ {faqs.map((faq, index) => (
218
+ <div key={index} className="bg-white rounded-2xl p-6 shadow-soft">
219
+ <h3 className="font-semibold text-warmgray-900 mb-2">{faq.q}</h3>
220
+ <p className="text-warmgray-600 text-sm">{faq.a}</p>
221
+ </div>
222
+ ))}
223
+ </div>
224
+
225
+ {/* Social Links */}
226
+ <div className="mt-8 bg-gradient-to-br from-teal-500 to-sage-500 rounded-2xl p-6 text-white">
227
+ <h3 className="font-semibold mb-4">Follow Us</h3>
228
+ <div className="flex gap-4">
229
+ {['Twitter', 'LinkedIn', 'YouTube', 'Discord'].map((social) => (
230
+ <a
231
+ key={social}
232
+ href="#"
233
+ className="bg-white/20 hover:bg-white/30 transition-colors px-4 py-2 rounded-lg text-sm font-medium"
234
+ >
235
+ {social}
236
+ </a>
237
+ ))}
238
+ </div>
239
+ </div>
240
+ </div>
241
+ </div>
242
+ </div>
243
+ </section>
244
+ </div>
245
+ );
246
+ }
app/courses/page.tsx ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import Link from 'next/link';
4
+ import { useState } from 'react';
5
+
6
+ export default function CoursesPage() {
7
+ const [selectedCategory, setSelectedCategory] = useState('all');
8
+
9
+ const categories = [
10
+ { id: 'all', name: 'All Courses' },
11
+ { id: 'beginner', name: 'Beginner' },
12
+ { id: 'intermediate', name: 'Intermediate' },
13
+ { id: 'advanced', name: 'Advanced' },
14
+ ];
15
+
16
+ const courses = [
17
+ {
18
+ id: 1,
19
+ title: 'Python Fundamentals',
20
+ description: 'Learn Python from scratch. Variables, data types, operators, and basic syntax.',
21
+ level: 'beginner',
22
+ duration: '4 weeks',
23
+ lessons: 24,
24
+ students: 1250,
25
+ rating: 4.8,
26
+ image: '🐍',
27
+ color: 'bg-teal-500',
28
+ },
29
+ {
30
+ id: 2,
31
+ title: 'Control Flow & Loops',
32
+ description: 'Master if statements, for loops, while loops, and conditional logic.',
33
+ level: 'beginner',
34
+ duration: '3 weeks',
35
+ lessons: 18,
36
+ students: 980,
37
+ rating: 4.7,
38
+ image: '🔄',
39
+ color: 'bg-sage-500',
40
+ },
41
+ {
42
+ id: 3,
43
+ title: 'Functions & Modules',
44
+ description: 'Create reusable code with functions, parameters, return values, and modules.',
45
+ level: 'intermediate',
46
+ duration: '4 weeks',
47
+ lessons: 22,
48
+ students: 756,
49
+ rating: 4.9,
50
+ image: '⚡',
51
+ color: 'bg-lavender-500',
52
+ },
53
+ {
54
+ id: 4,
55
+ title: 'Object-Oriented Programming',
56
+ description: 'Classes, objects, inheritance, polymorphism, and encapsulation in Python.',
57
+ level: 'intermediate',
58
+ duration: '5 weeks',
59
+ lessons: 30,
60
+ students: 645,
61
+ rating: 4.8,
62
+ image: '🏗️',
63
+ color: 'bg-coral-500',
64
+ },
65
+ {
66
+ id: 5,
67
+ title: 'Data Structures',
68
+ description: 'Lists, dictionaries, sets, tuples, and when to use each data structure.',
69
+ level: 'intermediate',
70
+ duration: '4 weeks',
71
+ lessons: 26,
72
+ students: 823,
73
+ rating: 4.7,
74
+ image: '📊',
75
+ color: 'bg-teal-600',
76
+ },
77
+ {
78
+ id: 6,
79
+ title: 'File Handling & APIs',
80
+ description: 'Read/write files, work with JSON, and consume REST APIs with Python.',
81
+ level: 'advanced',
82
+ duration: '3 weeks',
83
+ lessons: 20,
84
+ students: 432,
85
+ rating: 4.9,
86
+ image: '📁',
87
+ color: 'bg-sage-600',
88
+ },
89
+ {
90
+ id: 7,
91
+ title: 'Error Handling & Debugging',
92
+ description: 'Try-except blocks, custom exceptions, and debugging techniques.',
93
+ level: 'intermediate',
94
+ duration: '2 weeks',
95
+ lessons: 14,
96
+ students: 567,
97
+ rating: 4.6,
98
+ image: '🐛',
99
+ color: 'bg-lavender-600',
100
+ },
101
+ {
102
+ id: 8,
103
+ title: 'Python Projects',
104
+ description: 'Build real-world projects: CLI tools, web scrapers, and automation scripts.',
105
+ level: 'advanced',
106
+ duration: '6 weeks',
107
+ lessons: 35,
108
+ students: 389,
109
+ rating: 4.9,
110
+ image: '🚀',
111
+ color: 'bg-coral-600',
112
+ },
113
+ ];
114
+
115
+ const filteredCourses = selectedCategory === 'all'
116
+ ? courses
117
+ : courses.filter(course => course.level === selectedCategory);
118
+
119
+ return (
120
+ <div className="min-h-screen bg-gradient-to-b from-cream-50 to-white">
121
+ {/* Header */}
122
+ <header className="bg-white/80 backdrop-blur-md border-b border-warmgray-100 sticky top-0 z-50">
123
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
124
+ <div className="flex items-center justify-between h-16">
125
+ <Link href="/" className="flex items-center space-x-3">
126
+ <div className="w-10 h-10 bg-gradient-to-br from-teal-500 to-teal-600 rounded-xl flex items-center justify-center shadow-soft">
127
+ <span className="text-white font-bold text-lg">L</span>
128
+ </div>
129
+ <span className="text-xl font-bold text-warmgray-900">LearnFlow</span>
130
+ </Link>
131
+
132
+ <nav className="hidden md:flex items-center space-x-1">
133
+ {[
134
+ { name: 'Home', href: '/' },
135
+ { name: 'Courses', href: '/courses' },
136
+ { name: 'About', href: '/about' },
137
+ { name: 'Resources', href: '/resources' },
138
+ { name: 'Contact', href: '/contact' },
139
+ ].map((item) => (
140
+ <Link
141
+ key={item.name}
142
+ href={item.href}
143
+ className={`px-4 py-2 rounded-full text-sm font-medium transition-all duration-200 ${
144
+ item.name === 'Courses'
145
+ ? 'bg-teal-50 text-teal-700'
146
+ : 'text-warmgray-600 hover:text-teal-700 hover:bg-teal-50'
147
+ }`}
148
+ >
149
+ {item.name}
150
+ </Link>
151
+ ))}
152
+ </nav>
153
+
154
+ <div className="flex items-center space-x-3">
155
+ <Link href="/register" className="text-warmgray-700 hover:text-teal-700 font-medium text-sm">
156
+ Sign Up
157
+ </Link>
158
+ <Link href="/" className="bg-teal-600 text-white px-5 py-2.5 rounded-full hover:bg-teal-700 transition-all font-medium text-sm">
159
+ Login
160
+ </Link>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </header>
165
+
166
+ {/* Hero Section */}
167
+ <section className="py-16 px-4">
168
+ <div className="max-w-7xl mx-auto text-center">
169
+ <h1 className="text-4xl md:text-5xl font-bold text-warmgray-900 mb-4">
170
+ Explore Our <span className="text-teal-600">Python Courses</span>
171
+ </h1>
172
+ <p className="text-lg text-warmgray-600 max-w-2xl mx-auto">
173
+ From beginner to advanced, find the perfect course to master Python programming with AI-powered guidance.
174
+ </p>
175
+ </div>
176
+ </section>
177
+
178
+ {/* Category Filter */}
179
+ <section className="px-4 pb-8">
180
+ <div className="max-w-7xl mx-auto">
181
+ <div className="flex flex-wrap justify-center gap-3">
182
+ {categories.map((category) => (
183
+ <button
184
+ key={category.id}
185
+ onClick={() => setSelectedCategory(category.id)}
186
+ className={`px-6 py-2.5 rounded-full font-medium transition-all duration-200 ${
187
+ selectedCategory === category.id
188
+ ? 'bg-teal-600 text-white shadow-soft'
189
+ : 'bg-white text-warmgray-600 hover:bg-teal-50 hover:text-teal-700 border border-warmgray-200'
190
+ }`}
191
+ >
192
+ {category.name}
193
+ </button>
194
+ ))}
195
+ </div>
196
+ </div>
197
+ </section>
198
+
199
+ {/* Courses Grid */}
200
+ <section className="px-4 pb-20">
201
+ <div className="max-w-7xl mx-auto">
202
+ <div className="grid md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
203
+ {filteredCourses.map((course) => (
204
+ <div
205
+ key={course.id}
206
+ className="bg-white rounded-2xl shadow-soft hover:shadow-soft-lg transition-all duration-300 overflow-hidden group"
207
+ >
208
+ <div className={`${course.color} h-32 flex items-center justify-center`}>
209
+ <span className="text-5xl">{course.image}</span>
210
+ </div>
211
+ <div className="p-5">
212
+ <div className="flex items-center gap-2 mb-2">
213
+ <span className={`px-2.5 py-1 rounded-full text-xs font-medium ${
214
+ course.level === 'beginner' ? 'bg-green-100 text-green-700' :
215
+ course.level === 'intermediate' ? 'bg-yellow-100 text-yellow-700' :
216
+ 'bg-red-100 text-red-700'
217
+ }`}>
218
+ {course.level.charAt(0).toUpperCase() + course.level.slice(1)}
219
+ </span>
220
+ <span className="text-warmgray-400 text-xs">{course.duration}</span>
221
+ </div>
222
+ <h3 className="font-semibold text-warmgray-900 mb-2 group-hover:text-teal-600 transition-colors">
223
+ {course.title}
224
+ </h3>
225
+ <p className="text-sm text-warmgray-600 mb-4 line-clamp-2">
226
+ {course.description}
227
+ </p>
228
+ <div className="flex items-center justify-between text-sm">
229
+ <div className="flex items-center gap-3 text-warmgray-500">
230
+ <span>{course.lessons} lessons</span>
231
+ <span>{course.students} students</span>
232
+ </div>
233
+ <div className="flex items-center text-yellow-500">
234
+ <svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
235
+ <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
236
+ </svg>
237
+ <span className="ml-1 text-warmgray-700">{course.rating}</span>
238
+ </div>
239
+ </div>
240
+ <Link
241
+ href="/register"
242
+ className="mt-4 block w-full text-center bg-teal-50 text-teal-700 py-2.5 rounded-xl font-medium hover:bg-teal-100 transition-colors"
243
+ >
244
+ Enroll Now
245
+ </Link>
246
+ </div>
247
+ </div>
248
+ ))}
249
+ </div>
250
+ </div>
251
+ </section>
252
+
253
+ {/* CTA Section */}
254
+ <section className="py-16 px-4 bg-gradient-to-r from-teal-600 to-teal-700">
255
+ <div className="max-w-4xl mx-auto text-center text-white">
256
+ <h2 className="text-3xl font-bold mb-4">Ready to Start Learning?</h2>
257
+ <p className="text-teal-100 mb-8">Join thousands of students mastering Python with AI-powered tutoring.</p>
258
+ <Link
259
+ href="/register"
260
+ className="inline-block bg-white text-teal-700 px-8 py-3 rounded-full font-semibold hover:bg-cream-50 transition-colors shadow-lg"
261
+ >
262
+ Get Started Free
263
+ </Link>
264
+ </div>
265
+ </section>
266
+ </div>
267
+ );
268
+ }
app/globals.css ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ /* VeryWellMind-inspired Wellness Theme */
6
+ :root {
7
+ /* Primary Colors */
8
+ --primary-teal: #0d9488;
9
+ --primary-teal-light: #14b8a6;
10
+ --primary-teal-dark: #0f766e;
11
+
12
+ /* Accent Colors */
13
+ --accent-lavender: #a855f7;
14
+ --accent-coral: #ff6b6b;
15
+ --accent-sage: #7a8b63;
16
+
17
+ /* Background Colors */
18
+ --bg-cream: #fdf9f3;
19
+ --bg-soft: #fafaf9;
20
+ --bg-white: #ffffff;
21
+
22
+ /* Text Colors */
23
+ --text-primary: #1c1917;
24
+ --text-secondary: #57534e;
25
+ --text-muted: #78716c;
26
+
27
+ /* Foreground/Background */
28
+ --foreground-rgb: 28, 25, 23;
29
+ --background-rgb: 253, 249, 243;
30
+ }
31
+
32
+ @media (prefers-color-scheme: dark) {
33
+ :root {
34
+ --foreground-rgb: 250, 250, 249;
35
+ --background-rgb: 28, 25, 23;
36
+ }
37
+ }
38
+
39
+ * {
40
+ box-sizing: border-box;
41
+ padding: 0;
42
+ margin: 0;
43
+ }
44
+
45
+ html {
46
+ scroll-behavior: smooth;
47
+ }
48
+
49
+ body {
50
+ color: rgb(var(--foreground-rgb));
51
+ background: rgb(var(--background-rgb));
52
+ font-feature-settings: 'rlig' 1, 'calt' 1;
53
+ -webkit-font-smoothing: antialiased;
54
+ -moz-osx-font-smoothing: grayscale;
55
+ }
56
+
57
+ /* Wellness Typography */
58
+ @layer base {
59
+ h1, h2, h3, h4, h5, h6 {
60
+ @apply font-display tracking-tight;
61
+ }
62
+
63
+ h1 {
64
+ @apply text-4xl md:text-5xl lg:text-6xl font-bold leading-tight;
65
+ }
66
+
67
+ h2 {
68
+ @apply text-3xl md:text-4xl font-bold;
69
+ }
70
+
71
+ h3 {
72
+ @apply text-xl md:text-2xl font-semibold;
73
+ }
74
+
75
+ p {
76
+ @apply leading-relaxed;
77
+ }
78
+ }
79
+
80
+ /* Custom Components */
81
+ @layer components {
82
+ /* Wellness Card Style */
83
+ .wellness-card {
84
+ @apply bg-white rounded-2xl p-6 shadow-soft transition-all duration-300;
85
+ }
86
+
87
+ .wellness-card:hover {
88
+ @apply shadow-soft-lg -translate-y-1;
89
+ }
90
+
91
+ /* Soft Button Styles */
92
+ .btn-primary {
93
+ @apply bg-teal-600 text-white px-6 py-3 rounded-full font-medium
94
+ hover:bg-teal-700 transition-all duration-300
95
+ shadow-sm hover:shadow-md;
96
+ }
97
+
98
+ .btn-secondary {
99
+ @apply bg-white text-teal-700 px-6 py-3 rounded-full font-medium
100
+ border-2 border-teal-200 hover:border-teal-300
101
+ hover:bg-teal-50 transition-all duration-300;
102
+ }
103
+
104
+ .btn-soft {
105
+ @apply bg-cream-100 text-warmgray-700 px-6 py-3 rounded-full font-medium
106
+ hover:bg-cream-200 transition-all duration-300;
107
+ }
108
+
109
+ /* Category Pill */
110
+ .category-pill {
111
+ @apply inline-flex items-center px-4 py-2 rounded-full text-sm font-medium
112
+ transition-all duration-200;
113
+ }
114
+
115
+ .category-pill-teal {
116
+ @apply bg-teal-100 text-teal-800 hover:bg-teal-200;
117
+ }
118
+
119
+ .category-pill-lavender {
120
+ @apply bg-lavender-100 text-lavender-800 hover:bg-lavender-200;
121
+ }
122
+
123
+ .category-pill-coral {
124
+ @apply bg-coral-100 text-coral-800 hover:bg-coral-200;
125
+ }
126
+
127
+ .category-pill-sage {
128
+ @apply bg-sage-100 text-sage-800 hover:bg-sage-200;
129
+ }
130
+
131
+ /* Input Styles */
132
+ .input-wellness {
133
+ @apply w-full px-4 py-3 rounded-xl border-2 border-warmgray-200
134
+ bg-white focus:outline-none focus:border-teal-400
135
+ focus:ring-4 focus:ring-teal-100 transition-all duration-200
136
+ placeholder:text-warmgray-400;
137
+ }
138
+
139
+ /* Section Styles */
140
+ .section-wellness {
141
+ @apply py-16 md:py-24;
142
+ }
143
+
144
+ /* Gradient Backgrounds */
145
+ .bg-gradient-wellness {
146
+ background: linear-gradient(135deg, #f0fdfa 0%, #faf5ff 50%, #fdf9f3 100%);
147
+ }
148
+
149
+ .bg-gradient-hero {
150
+ background:
151
+ radial-gradient(circle at 30% 20%, rgba(20, 184, 166, 0.08) 0%, transparent 50%),
152
+ radial-gradient(circle at 70% 80%, rgba(168, 85, 247, 0.06) 0%, transparent 50%),
153
+ linear-gradient(180deg, #fdf9f3 0%, #ffffff 100%);
154
+ }
155
+
156
+ /* Decorative Elements */
157
+ .blob-teal {
158
+ @apply absolute rounded-full bg-teal-200/30 blur-3xl;
159
+ }
160
+
161
+ .blob-lavender {
162
+ @apply absolute rounded-full bg-lavender-200/30 blur-3xl;
163
+ }
164
+ }
165
+
166
+ @layer utilities {
167
+ .text-balance {
168
+ text-wrap: balance;
169
+ }
170
+
171
+ .animate-float {
172
+ animation: float 6s ease-in-out infinite;
173
+ }
174
+
175
+ @keyframes float {
176
+ 0%, 100% { transform: translateY(0px); }
177
+ 50% { transform: translateY(-10px); }
178
+ }
179
+
180
+ .animate-pulse-soft {
181
+ animation: pulse-soft 4s ease-in-out infinite;
182
+ }
183
+
184
+ @keyframes pulse-soft {
185
+ 0%, 100% { opacity: 1; }
186
+ 50% { opacity: 0.8; }
187
+ }
188
+ }
189
+
190
+ /* Custom Scrollbar */
191
+ ::-webkit-scrollbar {
192
+ width: 8px;
193
+ }
194
+
195
+ ::-webkit-scrollbar-track {
196
+ background: #f5f5f4;
197
+ }
198
+
199
+ ::-webkit-scrollbar-thumb {
200
+ background: #d6d3d1;
201
+ border-radius: 4px;
202
+ }
203
+
204
+ ::-webkit-scrollbar-thumb:hover {
205
+ background: #a8a29e;
206
+ }
207
+
208
+ /* Selection Color */
209
+ ::selection {
210
+ background-color: rgba(20, 184, 166, 0.2);
211
+ color: #0f766e;
212
+ }
app/layout.tsx ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import './globals.css';
2
+ import type { Metadata } from 'next';
3
+
4
+ export const metadata: Metadata = {
5
+ title: 'LearnFlow - AI-Powered Python Tutoring',
6
+ description: 'Interactive Python learning platform with AI tutors',
7
+ };
8
+
9
+ export default function RootLayout({
10
+ children,
11
+ }: {
12
+ children: React.ReactNode;
13
+ }) {
14
+ return (
15
+ <html lang="en">
16
+ <body className="font-sans antialiased">{children}</body>
17
+ </html>
18
+ );
19
+ }
app/page.tsx ADDED
@@ -0,0 +1,814 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import Link from 'next/link';
5
+ import { useRouter } from 'next/navigation';
6
+
7
+ const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
8
+
9
+ export default function Home() {
10
+ const router = useRouter();
11
+ const [role, setRole] = useState<'student' | 'teacher'>('student');
12
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
13
+ const [loginEmail, setLoginEmail] = useState('');
14
+ const [loginPassword, setLoginPassword] = useState('');
15
+ const [loginError, setLoginError] = useState('');
16
+ const [isLoggingIn, setIsLoggingIn] = useState(false);
17
+
18
+ const handleLogin = async (e: React.FormEvent) => {
19
+ e.preventDefault();
20
+ setLoginError('');
21
+ setIsLoggingIn(true);
22
+
23
+ try {
24
+ let user;
25
+ let token;
26
+
27
+ // Try API login first
28
+ try {
29
+ const response = await fetch(`${API_URL}/auth/login`, {
30
+ method: 'POST',
31
+ headers: { 'Content-Type': 'application/json' },
32
+ body: JSON.stringify({
33
+ email: loginEmail,
34
+ password: loginPassword,
35
+ }),
36
+ });
37
+
38
+ if (response.ok) {
39
+ const data = await response.json();
40
+ user = data.user;
41
+ token = data.token;
42
+ localStorage.setItem('learnflow_token', token);
43
+ } else if (response.status === 401) {
44
+ setLoginError('Invalid email or password');
45
+ setIsLoggingIn(false);
46
+ return;
47
+ } else {
48
+ throw new Error('API not available');
49
+ }
50
+ } catch (apiError) {
51
+ // Fallback to localStorage
52
+ console.log('Using localStorage fallback for login');
53
+ const users = JSON.parse(localStorage.getItem('learnflow_users') || '[]');
54
+ user = users.find((u: any) => u.email === loginEmail && u.password === loginPassword);
55
+
56
+ if (!user) {
57
+ setLoginError('Invalid email or password');
58
+ setIsLoggingIn(false);
59
+ return;
60
+ }
61
+ }
62
+
63
+ // Check if role matches
64
+ if (user.role !== role) {
65
+ setLoginError(`This account is registered as a ${user.role}. Please select the correct role.`);
66
+ setIsLoggingIn(false);
67
+ return;
68
+ }
69
+
70
+ // Set current user session
71
+ localStorage.setItem('learnflow_current_user', JSON.stringify({
72
+ id: user.id,
73
+ name: user.name,
74
+ email: user.email,
75
+ role: user.role,
76
+ }));
77
+
78
+ // Redirect based on role
79
+ if (role === 'student') {
80
+ router.push('/student/dashboard');
81
+ } else {
82
+ router.push('/teacher/dashboard');
83
+ }
84
+ } catch (err) {
85
+ setLoginError('Something went wrong. Please try again.');
86
+ setIsLoggingIn(false);
87
+ }
88
+ };
89
+
90
+ const categories = [
91
+ { name: 'Python Basics', color: 'teal', icon: '🐍' },
92
+ { name: 'Data Science', color: 'lavender', icon: '📊' },
93
+ { name: 'Web Dev', color: 'coral', icon: '🌐' },
94
+ { name: 'AI & ML', color: 'sage', icon: '🤖' },
95
+ ];
96
+
97
+ const features = [
98
+ {
99
+ icon: (
100
+ <svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
101
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
102
+ </svg>
103
+ ),
104
+ title: 'AI-Powered Learning',
105
+ description: 'Personalized learning paths that adapt to your unique pace and style',
106
+ color: 'teal',
107
+ },
108
+ {
109
+ icon: (
110
+ <svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
111
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
112
+ </svg>
113
+ ),
114
+ title: 'Interactive Coding',
115
+ description: 'Practice with real-time code execution and instant feedback',
116
+ color: 'lavender',
117
+ },
118
+ {
119
+ icon: (
120
+ <svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
121
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z" />
122
+ </svg>
123
+ ),
124
+ title: 'Expert Community',
125
+ description: 'Connect with mentors and peers who support your learning journey',
126
+ color: 'coral',
127
+ },
128
+ {
129
+ icon: (
130
+ <svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
131
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
132
+ </svg>
133
+ ),
134
+ title: 'Verified Certificates',
135
+ description: 'Earn industry-recognized credentials that boost your career',
136
+ color: 'sage',
137
+ },
138
+ ];
139
+
140
+ const courses = [
141
+ {
142
+ title: 'Python for Beginners',
143
+ description: 'Start your coding journey with the most beginner-friendly language',
144
+ duration: '8 weeks',
145
+ level: 'Beginner',
146
+ rating: 4.9,
147
+ students: '15,000+',
148
+ image: '🐍',
149
+ color: 'teal',
150
+ },
151
+ {
152
+ title: 'Data Science Essentials',
153
+ description: 'Master data analysis, visualization, and machine learning fundamentals',
154
+ duration: '12 weeks',
155
+ level: 'Intermediate',
156
+ rating: 4.8,
157
+ students: '12,000+',
158
+ image: '📊',
159
+ color: 'lavender',
160
+ },
161
+ {
162
+ title: 'Full Stack Web Development',
163
+ description: 'Build modern web applications from frontend to backend',
164
+ duration: '16 weeks',
165
+ level: 'Intermediate',
166
+ rating: 4.7,
167
+ students: '10,000+',
168
+ image: '🌐',
169
+ color: 'coral',
170
+ },
171
+ ];
172
+
173
+ const testimonials = [
174
+ {
175
+ quote: "LearnFlow transformed my career. The AI tutor felt like having a personal mentor available 24/7.",
176
+ name: "Sarah Ahmed",
177
+ role: "Software Developer",
178
+ avatar: "SA",
179
+ },
180
+ {
181
+ quote: "The interactive coding exercises made learning Python actually fun. I went from zero to building apps in weeks.",
182
+ name: "Ali Hassan",
183
+ role: "Data Analyst",
184
+ avatar: "AH",
185
+ },
186
+ {
187
+ quote: "Finally, a learning platform that adapts to my pace. No more feeling left behind or bored.",
188
+ name: "Fatima Khan",
189
+ role: "Web Developer",
190
+ avatar: "FK",
191
+ },
192
+ ];
193
+
194
+ return (
195
+ <div className="min-h-screen bg-cream-50">
196
+ {/* Header */}
197
+ <header className="bg-white/80 backdrop-blur-md border-b border-warmgray-100 sticky top-0 z-50">
198
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
199
+ <div className="flex justify-between items-center h-16">
200
+ <div className="flex items-center">
201
+ <div className="flex-shrink-0 flex items-center">
202
+ <div className="w-10 h-10 bg-gradient-to-br from-teal-500 to-teal-600 rounded-xl flex items-center justify-center shadow-soft">
203
+ <span className="text-white font-bold text-lg">LF</span>
204
+ </div>
205
+ <span className="ml-3 text-xl font-bold text-warmgray-900">LearnFlow</span>
206
+ </div>
207
+ </div>
208
+
209
+ <nav className="hidden md:flex items-center space-x-1">
210
+ {[
211
+ { name: 'Home', href: '/' },
212
+ { name: 'Courses', href: '/courses' },
213
+ { name: 'About', href: '/about' },
214
+ { name: 'Resources', href: '/resources' },
215
+ { name: 'Contact', href: '/contact' },
216
+ ].map((item, i) => (
217
+ <Link
218
+ key={item.name}
219
+ href={item.href}
220
+ className={`px-4 py-2 rounded-full text-sm font-medium transition-all duration-200 ${
221
+ i === 0
222
+ ? 'bg-teal-50 text-teal-700'
223
+ : 'text-warmgray-600 hover:text-teal-700 hover:bg-teal-50'
224
+ }`}
225
+ >
226
+ {item.name}
227
+ </Link>
228
+ ))}
229
+ </nav>
230
+
231
+ <div className="hidden md:flex items-center space-x-3">
232
+ <Link
233
+ href="/register"
234
+ className="text-warmgray-700 hover:text-teal-700 font-medium text-sm transition-colors px-4 py-2"
235
+ >
236
+ Sign Up
237
+ </Link>
238
+ <a
239
+ href="#login"
240
+ className="bg-teal-600 text-white px-5 py-2.5 rounded-full hover:bg-teal-700 transition-all duration-300 font-medium text-sm shadow-soft hover:shadow-md"
241
+ >
242
+ Login
243
+ </a>
244
+ </div>
245
+
246
+ <div className="md:hidden flex items-center">
247
+ <button
248
+ onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
249
+ className="text-warmgray-700 hover:text-teal-600 p-2 rounded-lg hover:bg-teal-50 transition-colors"
250
+ >
251
+ <svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
252
+ {mobileMenuOpen ? (
253
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
254
+ ) : (
255
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
256
+ )}
257
+ </svg>
258
+ </button>
259
+ </div>
260
+ </div>
261
+
262
+ {mobileMenuOpen && (
263
+ <div className="md:hidden py-4 border-t border-warmgray-100 bg-white/95 backdrop-blur-md absolute left-0 right-0 shadow-soft-lg">
264
+ <div className="flex flex-col space-y-1 px-4">
265
+ {[
266
+ { name: 'Home', href: '/' },
267
+ { name: 'Courses', href: '/courses' },
268
+ { name: 'About', href: '/about' },
269
+ { name: 'Resources', href: '/resources' },
270
+ { name: 'Contact', href: '/contact' },
271
+ ].map((item, i) => (
272
+ <Link
273
+ key={item.name}
274
+ href={item.href}
275
+ className={`px-4 py-3 rounded-xl font-medium transition-colors ${
276
+ i === 0 ? 'bg-teal-50 text-teal-700' : 'text-warmgray-700 hover:bg-teal-50 hover:text-teal-700'
277
+ }`}
278
+ >
279
+ {item.name}
280
+ </Link>
281
+ ))}
282
+ <div className="pt-4 mt-2 flex flex-col space-y-3 border-t border-warmgray-100">
283
+ <Link href="/register" className="text-teal-600 hover:text-teal-700 font-medium px-4 py-2">
284
+ Sign Up
285
+ </Link>
286
+ <a
287
+ href="#login"
288
+ className="bg-teal-600 text-white px-4 py-3 rounded-xl text-center hover:bg-teal-700 transition-colors font-medium"
289
+ >
290
+ Login
291
+ </a>
292
+ </div>
293
+ </div>
294
+ </div>
295
+ )}
296
+ </div>
297
+ </header>
298
+
299
+ {/* Hero Section */}
300
+ <section className="relative overflow-hidden bg-gradient-hero">
301
+ {/* Decorative blobs */}
302
+ <div className="blob-teal w-96 h-96 -top-48 -left-48 opacity-60" />
303
+ <div className="blob-lavender w-80 h-80 top-20 right-0 opacity-40" />
304
+
305
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-16 md:py-24 relative">
306
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
307
+ <div className="text-center lg:text-left">
308
+ <div className="inline-flex items-center bg-teal-100 text-teal-800 px-4 py-2 rounded-full text-sm font-medium mb-6">
309
+ <span className="w-2 h-2 bg-teal-500 rounded-full mr-2 animate-pulse" />
310
+ AI-Powered Learning Platform
311
+ </div>
312
+ <h1 className="text-warmgray-900 mb-6 text-balance">
313
+ Your Journey to{' '}
314
+ <span className="text-transparent bg-clip-text bg-gradient-to-r from-teal-600 to-teal-500">
315
+ Programming Mastery
316
+ </span>{' '}
317
+ Starts Here
318
+ </h1>
319
+ <p className="text-lg md:text-xl text-warmgray-600 mb-8 leading-relaxed max-w-xl mx-auto lg:mx-0">
320
+ Experience personalized learning with AI tutors that understand your pace, answer your questions, and guide you every step of the way.
321
+ </p>
322
+ <div className="flex flex-col sm:flex-row gap-4 justify-center lg:justify-start">
323
+ <Link href="/register" className="btn-primary inline-flex items-center justify-center">
324
+ Start Learning Free
325
+ <svg className="w-5 h-5 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
326
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
327
+ </svg>
328
+ </Link>
329
+ <a href="#courses" className="btn-secondary inline-flex items-center justify-center">
330
+ Explore Courses
331
+ </a>
332
+ </div>
333
+
334
+ {/* Trust badges */}
335
+ <div className="mt-10 flex flex-wrap items-center justify-center lg:justify-start gap-6 text-sm text-warmgray-500">
336
+ <div className="flex items-center">
337
+ <svg className="w-5 h-5 text-teal-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
338
+ <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
339
+ </svg>
340
+ 50,000+ Students
341
+ </div>
342
+ <div className="flex items-center">
343
+ <svg className="w-5 h-5 text-teal-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
344
+ <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
345
+ </svg>
346
+ 95% Success Rate
347
+ </div>
348
+ <div className="flex items-center">
349
+ <svg className="w-5 h-5 text-teal-500 mr-2" fill="currentColor" viewBox="0 0 20 20">
350
+ <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
351
+ </svg>
352
+ 24/7 Support
353
+ </div>
354
+ </div>
355
+ </div>
356
+
357
+ {/* Hero Card */}
358
+ <div className="relative">
359
+ <div className="bg-white rounded-3xl p-8 shadow-soft-lg relative z-10">
360
+ <div className="text-center mb-6">
361
+ <div className="w-20 h-20 bg-gradient-to-br from-teal-400 to-teal-600 rounded-2xl flex items-center justify-center mx-auto mb-4 shadow-soft animate-float">
362
+ <span className="text-4xl">🎓</span>
363
+ </div>
364
+ <h3 className="text-xl font-bold text-warmgray-900 mb-2">Start Your Learning Journey</h3>
365
+ <p className="text-warmgray-600">Interactive Python tutoring with real-time AI feedback</p>
366
+ </div>
367
+
368
+ <div className="grid grid-cols-2 gap-4">
369
+ {[
370
+ { value: '50K+', label: 'Students', bg: 'bg-teal-50', text: 'text-teal-700' },
371
+ { value: '100+', label: 'Courses', bg: 'bg-lavender-50', text: 'text-lavender-700' },
372
+ { value: '95%', label: 'Success', bg: 'bg-coral-50', text: 'text-coral-700' },
373
+ { value: '24/7', label: 'Support', bg: 'bg-sage-50', text: 'text-sage-700' },
374
+ ].map((stat) => (
375
+ <div key={stat.label} className={`${stat.bg} p-4 rounded-2xl text-center`}>
376
+ <div className={`text-2xl font-bold ${stat.text}`}>{stat.value}</div>
377
+ <div className="text-sm text-warmgray-600">{stat.label}</div>
378
+ </div>
379
+ ))}
380
+ </div>
381
+ </div>
382
+
383
+ {/* Decorative elements */}
384
+ <div className="absolute -bottom-4 -right-4 w-32 h-32 bg-lavender-200 rounded-2xl -z-10 opacity-50" />
385
+ <div className="absolute -top-4 -left-4 w-24 h-24 bg-teal-200 rounded-2xl -z-10 opacity-50" />
386
+ </div>
387
+ </div>
388
+ </div>
389
+ </section>
390
+
391
+ {/* Categories Section */}
392
+ <section className="py-12 bg-white">
393
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
394
+ <div className="flex flex-wrap justify-center gap-3">
395
+ {categories.map((cat) => (
396
+ <button
397
+ key={cat.name}
398
+ className={`category-pill category-pill-${cat.color} flex items-center gap-2`}
399
+ >
400
+ <span>{cat.icon}</span>
401
+ {cat.name}
402
+ </button>
403
+ ))}
404
+ </div>
405
+ </div>
406
+ </section>
407
+
408
+ {/* Features Section */}
409
+ <section className="section-wellness bg-white">
410
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
411
+ <div className="text-center mb-16">
412
+ <h2 className="text-warmgray-900 mb-4">Why Choose LearnFlow?</h2>
413
+ <p className="text-lg text-warmgray-600 max-w-2xl mx-auto">
414
+ Our platform combines cutting-edge AI with proven learning methods to create an experience that's effective and enjoyable
415
+ </p>
416
+ </div>
417
+
418
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
419
+ {features.map((feature) => (
420
+ <div key={feature.title} className="wellness-card text-center group">
421
+ <div
422
+ className={`w-16 h-16 mx-auto mb-6 rounded-2xl flex items-center justify-center transition-transform duration-300 group-hover:scale-110 ${
423
+ feature.color === 'teal' ? 'bg-teal-100 text-teal-600' :
424
+ feature.color === 'lavender' ? 'bg-lavender-100 text-lavender-600' :
425
+ feature.color === 'coral' ? 'bg-coral-100 text-coral-600' :
426
+ 'bg-sage-100 text-sage-600'
427
+ }`}
428
+ >
429
+ {feature.icon}
430
+ </div>
431
+ <h3 className="text-lg font-bold text-warmgray-900 mb-3">{feature.title}</h3>
432
+ <p className="text-warmgray-600 text-sm leading-relaxed">{feature.description}</p>
433
+ </div>
434
+ ))}
435
+ </div>
436
+ </div>
437
+ </section>
438
+
439
+ {/* Courses Section */}
440
+ <section id="courses" className="section-wellness bg-gradient-wellness">
441
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
442
+ <div className="text-center mb-16">
443
+ <h2 className="text-warmgray-900 mb-4">Popular Courses</h2>
444
+ <p className="text-lg text-warmgray-600 max-w-2xl mx-auto">
445
+ Choose from our carefully crafted programs designed to take you from beginner to professional
446
+ </p>
447
+ </div>
448
+
449
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
450
+ {courses.map((course) => (
451
+ <div key={course.title} className="wellness-card group">
452
+ <div className="flex items-start justify-between mb-4">
453
+ <div
454
+ className={`w-14 h-14 rounded-2xl flex items-center justify-center text-2xl ${
455
+ course.color === 'teal' ? 'bg-teal-100' :
456
+ course.color === 'lavender' ? 'bg-lavender-100' :
457
+ 'bg-coral-100'
458
+ }`}
459
+ >
460
+ {course.image}
461
+ </div>
462
+ <span
463
+ className={`px-3 py-1 rounded-full text-xs font-medium ${
464
+ course.color === 'teal' ? 'bg-teal-100 text-teal-700' :
465
+ course.color === 'lavender' ? 'bg-lavender-100 text-lavender-700' :
466
+ 'bg-coral-100 text-coral-700'
467
+ }`}
468
+ >
469
+ {course.level}
470
+ </span>
471
+ </div>
472
+
473
+ <h3 className="text-lg font-bold text-warmgray-900 mb-2">{course.title}</h3>
474
+ <p className="text-warmgray-600 text-sm mb-4 leading-relaxed">{course.description}</p>
475
+
476
+ <div className="flex items-center justify-between text-sm text-warmgray-500 mb-4">
477
+ <span className="flex items-center">
478
+ <svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
479
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
480
+ </svg>
481
+ {course.duration}
482
+ </span>
483
+ <span className="flex items-center">
484
+ <svg className="w-4 h-4 mr-1 text-yellow-500" fill="currentColor" viewBox="0 0 20 20">
485
+ <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
486
+ </svg>
487
+ {course.rating}
488
+ </span>
489
+ <span>{course.students}</span>
490
+ </div>
491
+
492
+ <button
493
+ className={`w-full py-3 rounded-xl font-medium transition-all duration-300 ${
494
+ course.color === 'teal' ? 'bg-teal-600 hover:bg-teal-700 text-white' :
495
+ course.color === 'lavender' ? 'bg-lavender-600 hover:bg-lavender-700 text-white' :
496
+ 'bg-coral-600 hover:bg-coral-700 text-white'
497
+ }`}
498
+ >
499
+ Enroll Now
500
+ </button>
501
+ </div>
502
+ ))}
503
+ </div>
504
+
505
+ <div className="text-center mt-12">
506
+ <a href="#" className="btn-secondary inline-flex items-center">
507
+ View All Courses
508
+ <svg className="w-5 h-5 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
509
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 7l5 5m0 0l-5 5m5-5H6" />
510
+ </svg>
511
+ </a>
512
+ </div>
513
+ </div>
514
+ </section>
515
+
516
+ {/* Testimonials Section */}
517
+ <section className="section-wellness bg-white">
518
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
519
+ <div className="text-center mb-16">
520
+ <h2 className="text-warmgray-900 mb-4">What Our Students Say</h2>
521
+ <p className="text-lg text-warmgray-600 max-w-2xl mx-auto">
522
+ Join thousands of learners who have transformed their careers with LearnFlow
523
+ </p>
524
+ </div>
525
+
526
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
527
+ {testimonials.map((testimonial, index) => (
528
+ <div key={index} className="wellness-card">
529
+ <div className="flex items-center mb-4">
530
+ {[...Array(5)].map((_, i) => (
531
+ <svg key={i} className="w-5 h-5 text-yellow-400" fill="currentColor" viewBox="0 0 20 20">
532
+ <path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
533
+ </svg>
534
+ ))}
535
+ </div>
536
+ <p className="text-warmgray-700 mb-6 italic leading-relaxed">"{testimonial.quote}"</p>
537
+ <div className="flex items-center">
538
+ <div className="w-12 h-12 bg-gradient-to-br from-teal-400 to-teal-600 rounded-full flex items-center justify-center text-white font-bold">
539
+ {testimonial.avatar}
540
+ </div>
541
+ <div className="ml-4">
542
+ <div className="font-semibold text-warmgray-900">{testimonial.name}</div>
543
+ <div className="text-sm text-warmgray-500">{testimonial.role}</div>
544
+ </div>
545
+ </div>
546
+ </div>
547
+ ))}
548
+ </div>
549
+ </div>
550
+ </section>
551
+
552
+ {/* Login Section */}
553
+ <section id="login" className="section-wellness bg-gradient-wellness">
554
+ <div className="max-w-xl mx-auto px-4 sm:px-6 lg:px-8">
555
+ <div className="bg-white rounded-3xl p-8 md:p-10 shadow-soft-lg">
556
+ <div className="text-center mb-8">
557
+ <h2 className="text-2xl font-bold text-warmgray-900 mb-2">Welcome Back</h2>
558
+ <p className="text-warmgray-600">Access your personalized learning dashboard</p>
559
+ </div>
560
+
561
+ <div className="flex justify-center gap-2 mb-8 bg-warmgray-100 p-1.5 rounded-full">
562
+ <button
563
+ onClick={() => setRole('student')}
564
+ className={`flex-1 px-6 py-2.5 rounded-full font-medium text-sm transition-all duration-300 ${
565
+ role === 'student'
566
+ ? 'bg-teal-600 text-white shadow-soft'
567
+ : 'text-warmgray-600 hover:text-warmgray-900'
568
+ }`}
569
+ >
570
+ Student
571
+ </button>
572
+ <button
573
+ onClick={() => setRole('teacher')}
574
+ className={`flex-1 px-6 py-2.5 rounded-full font-medium text-sm transition-all duration-300 ${
575
+ role === 'teacher'
576
+ ? 'bg-lavender-600 text-white shadow-soft'
577
+ : 'text-warmgray-600 hover:text-warmgray-900'
578
+ }`}
579
+ >
580
+ Teacher
581
+ </button>
582
+ </div>
583
+
584
+ {/* Login Error */}
585
+ {loginError && (
586
+ <div className="mb-6 p-4 bg-coral-50 border border-coral-200 rounded-xl flex items-center text-coral-700">
587
+ <svg className="w-5 h-5 mr-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
588
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
589
+ </svg>
590
+ <span className="text-sm">{loginError}</span>
591
+ </div>
592
+ )}
593
+
594
+ <form onSubmit={handleLogin} className="space-y-5">
595
+ <div>
596
+ <label htmlFor="login-email" className="block text-sm font-medium text-warmgray-700 mb-2">
597
+ Email Address
598
+ </label>
599
+ <input
600
+ type="email"
601
+ id="login-email"
602
+ name="email"
603
+ required
604
+ value={loginEmail}
605
+ onChange={(e) => { setLoginEmail(e.target.value); setLoginError(''); }}
606
+ className="input-wellness"
607
+ placeholder="you@example.com"
608
+ disabled={isLoggingIn}
609
+ />
610
+ </div>
611
+ <div>
612
+ <label htmlFor="login-password" className="block text-sm font-medium text-warmgray-700 mb-2">
613
+ Password
614
+ </label>
615
+ <input
616
+ type="password"
617
+ id="login-password"
618
+ name="password"
619
+ required
620
+ value={loginPassword}
621
+ onChange={(e) => { setLoginPassword(e.target.value); setLoginError(''); }}
622
+ className="input-wellness"
623
+ placeholder="Enter your password"
624
+ disabled={isLoggingIn}
625
+ />
626
+ </div>
627
+ <div className="flex items-center justify-between">
628
+ <div className="flex items-center">
629
+ <input
630
+ id="remember-me"
631
+ name="remember-me"
632
+ type="checkbox"
633
+ className="h-4 w-4 text-teal-600 focus:ring-teal-500 border-warmgray-300 rounded"
634
+ />
635
+ <label htmlFor="remember-me" className="ml-2 block text-sm text-warmgray-700">
636
+ Remember me
637
+ </label>
638
+ </div>
639
+ <a href="#" className="text-sm text-teal-600 hover:text-teal-700 font-medium">
640
+ Forgot password?
641
+ </a>
642
+ </div>
643
+ <button
644
+ type="submit"
645
+ disabled={isLoggingIn}
646
+ className={`w-full py-3 rounded-xl font-medium transition-all duration-300 flex items-center justify-center ${
647
+ role === 'student'
648
+ ? 'bg-teal-600 hover:bg-teal-700 text-white'
649
+ : 'bg-lavender-600 hover:bg-lavender-700 text-white'
650
+ } ${isLoggingIn ? 'opacity-70 cursor-not-allowed' : ''}`}
651
+ >
652
+ {isLoggingIn ? (
653
+ <>
654
+ <svg className="animate-spin -ml-1 mr-3 h-5 w-5 text-white" fill="none" viewBox="0 0 24 24">
655
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
656
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
657
+ </svg>
658
+ Signing In...
659
+ </>
660
+ ) : (
661
+ 'Sign In'
662
+ )}
663
+ </button>
664
+ </form>
665
+
666
+ <p className="text-center mt-6 text-sm text-warmgray-600">
667
+ Don't have an account?{' '}
668
+ <Link href="/register" className="text-teal-600 hover:text-teal-700 font-medium">
669
+ Sign up for free
670
+ </Link>
671
+ </p>
672
+ </div>
673
+ </div>
674
+ </section>
675
+
676
+ {/* Newsletter Section */}
677
+ <section className="py-16 bg-teal-700">
678
+ <div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
679
+ <h2 className="text-2xl md:text-3xl font-bold text-white mb-4">
680
+ Stay Updated with Latest Courses
681
+ </h2>
682
+ <p className="text-teal-100 mb-8 max-w-xl mx-auto">
683
+ Subscribe to our newsletter and get notified about new courses, tips, and exclusive offers
684
+ </p>
685
+ <form className="flex flex-col sm:flex-row gap-4 max-w-md mx-auto">
686
+ <input
687
+ type="email"
688
+ placeholder="Enter your email"
689
+ className="flex-1 px-5 py-3 rounded-full bg-white/10 border border-white/20 text-white placeholder:text-teal-200 focus:outline-none focus:ring-2 focus:ring-white/30"
690
+ />
691
+ <button
692
+ type="submit"
693
+ className="bg-white text-teal-700 px-8 py-3 rounded-full font-medium hover:bg-teal-50 transition-colors"
694
+ >
695
+ Subscribe
696
+ </button>
697
+ </form>
698
+ </div>
699
+ </section>
700
+
701
+ {/* Footer */}
702
+ <footer className="bg-warmgray-900 text-white">
703
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
704
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mb-12">
705
+ <div>
706
+ <div className="flex items-center mb-6">
707
+ <div className="w-10 h-10 bg-gradient-to-br from-teal-400 to-teal-600 rounded-xl flex items-center justify-center">
708
+ <span className="text-white font-bold">LF</span>
709
+ </div>
710
+ <span className="ml-3 text-lg font-bold">LearnFlow</span>
711
+ </div>
712
+ <p className="text-warmgray-400 text-sm leading-relaxed mb-6">
713
+ Empowering the next generation of developers with AI-powered learning experiences that adapt to your unique journey.
714
+ </p>
715
+ <div className="flex space-x-4">
716
+ {['facebook', 'twitter', 'linkedin', 'instagram'].map((social) => (
717
+ <a
718
+ key={social}
719
+ href="#"
720
+ className="w-10 h-10 bg-warmgray-800 hover:bg-teal-600 rounded-full flex items-center justify-center transition-colors"
721
+ >
722
+ <span className="sr-only">{social}</span>
723
+ <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
724
+ {social === 'facebook' && (
725
+ <path fillRule="evenodd" d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z" clipRule="evenodd" />
726
+ )}
727
+ {social === 'twitter' && (
728
+ <path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
729
+ )}
730
+ {social === 'linkedin' && (
731
+ <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
732
+ )}
733
+ {social === 'instagram' && (
734
+ <path fillRule="evenodd" d="M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.067.06 1.407.06 4.123v.08c0 2.643-.012 2.987-.06 4.043-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.067.048-1.407.06-4.123.06h-.08c-2.643 0-2.987-.012-4.043-.06-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.047-1.024-.06-1.379-.06-3.808v-.63c0-2.43.013-2.784.06-3.808.049-1.064.218-1.791.465-2.427a4.902 4.902 0 011.153-1.772A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802h-.468c-2.456 0-2.784.011-3.807.058-.975.045-1.504.207-1.857.344-.467.182-.8.398-1.15.748-.35.35-.566.683-.748 1.15-.137.353-.3.882-.344 1.857-.047 1.023-.058 1.351-.058 3.807v.468c0 2.456.011 2.784.058 3.807.045.975.207 1.504.344 1.857.182.466.399.8.748 1.15.35.35.683.566 1.15.748.353.137.882.3 1.857.344 1.054.048 1.37.058 4.041.058h.08c2.597 0 2.917-.01 3.96-.058.976-.045 1.505-.207 1.858-.344.466-.182.8-.398 1.15-.748.35-.35.566-.683.748-1.15.137-.353.3-.882.344-1.857.048-1.055.058-1.37.058-4.041v-.08c0-2.597-.01-2.917-.058-3.96-.045-.976-.207-1.505-.344-1.858a3.097 3.097 0 00-.748-1.15 3.098 3.098 0 00-1.15-.748c-.353-.137-.882-.3-1.857-.344-1.023-.047-1.351-.058-3.807-.058zM12 6.865a5.135 5.135 0 110 10.27 5.135 5.135 0 010-10.27zm0 1.802a3.333 3.333 0 100 6.666 3.333 3.333 0 000-6.666zm5.338-3.205a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z" clipRule="evenodd" />
735
+ )}
736
+ </svg>
737
+ </a>
738
+ ))}
739
+ </div>
740
+ </div>
741
+
742
+ <div>
743
+ <h3 className="text-sm font-semibold uppercase tracking-wider mb-4">Quick Links</h3>
744
+ <ul className="space-y-3">
745
+ {['About Us', 'Courses', 'Instructors', 'Blog', 'Careers'].map((link) => (
746
+ <li key={link}>
747
+ <a href="#" className="text-warmgray-400 hover:text-teal-400 transition-colors text-sm">
748
+ {link}
749
+ </a>
750
+ </li>
751
+ ))}
752
+ </ul>
753
+ </div>
754
+
755
+ <div>
756
+ <h3 className="text-sm font-semibold uppercase tracking-wider mb-4">Programs</h3>
757
+ <ul className="space-y-3">
758
+ {['Python Programming', 'Data Science', 'Web Development', 'Machine Learning', 'Cyber Security'].map((link) => (
759
+ <li key={link}>
760
+ <a href="#" className="text-warmgray-400 hover:text-teal-400 transition-colors text-sm">
761
+ {link}
762
+ </a>
763
+ </li>
764
+ ))}
765
+ </ul>
766
+ </div>
767
+
768
+ <div>
769
+ <h3 className="text-sm font-semibold uppercase tracking-wider mb-4">Contact</h3>
770
+ <ul className="space-y-3 text-sm text-warmgray-400">
771
+ <li className="flex items-start">
772
+ <svg className="w-5 h-5 mr-3 mt-0.5 text-teal-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
773
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
774
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
775
+ </svg>
776
+ 123 Education Street, Karachi, Pakistan
777
+ </li>
778
+ <li className="flex items-center">
779
+ <svg className="w-5 h-5 mr-3 text-teal-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
780
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
781
+ </svg>
782
+ info@learnflow.edu.pk
783
+ </li>
784
+ <li className="flex items-center">
785
+ <svg className="w-5 h-5 mr-3 text-teal-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
786
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
787
+ </svg>
788
+ +92 300 1234567
789
+ </li>
790
+ </ul>
791
+ </div>
792
+ </div>
793
+
794
+ <div className="border-t border-warmgray-800 pt-8 flex flex-col md:flex-row justify-between items-center">
795
+ <p className="text-sm text-warmgray-400">
796
+ &copy; 2026 LearnFlow. All rights reserved.
797
+ </p>
798
+ <div className="flex space-x-6 mt-4 md:mt-0">
799
+ <a href="#" className="text-sm text-warmgray-400 hover:text-teal-400 transition-colors">
800
+ Privacy Policy
801
+ </a>
802
+ <a href="#" className="text-sm text-warmgray-400 hover:text-teal-400 transition-colors">
803
+ Terms of Service
804
+ </a>
805
+ <a href="#" className="text-sm text-warmgray-400 hover:text-teal-400 transition-colors">
806
+ Cookie Policy
807
+ </a>
808
+ </div>
809
+ </div>
810
+ </div>
811
+ </footer>
812
+ </div>
813
+ );
814
+ }
app/register/page.tsx ADDED
@@ -0,0 +1,331 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import Link from 'next/link';
5
+ import { useRouter } from 'next/navigation';
6
+
7
+ const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
8
+
9
+ export default function RegisterPage() {
10
+ const router = useRouter();
11
+ const [isStudent, setIsStudent] = useState(true);
12
+ const [isLoading, setIsLoading] = useState(false);
13
+ const [error, setError] = useState('');
14
+ const [formData, setFormData] = useState({
15
+ name: '',
16
+ email: '',
17
+ password: '',
18
+ confirmPassword: '',
19
+ });
20
+
21
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
22
+ const { name, value } = e.target;
23
+ setFormData(prev => ({ ...prev, [name]: value }));
24
+ setError(''); // Clear error when user types
25
+ };
26
+
27
+ const handleRoleChange = (student: boolean) => {
28
+ setIsStudent(student);
29
+ setError('');
30
+ };
31
+
32
+ const handleSubmit = async (e: React.FormEvent) => {
33
+ e.preventDefault();
34
+ setError('');
35
+ setIsLoading(true);
36
+
37
+ // Validation
38
+ if (!formData.name.trim()) {
39
+ setError('Please enter your full name');
40
+ setIsLoading(false);
41
+ return;
42
+ }
43
+
44
+ if (!formData.email.trim()) {
45
+ setError('Please enter your email');
46
+ setIsLoading(false);
47
+ return;
48
+ }
49
+
50
+ if (formData.password.length < 6) {
51
+ setError('Password must be at least 6 characters');
52
+ setIsLoading(false);
53
+ return;
54
+ }
55
+
56
+ if (formData.password !== formData.confirmPassword) {
57
+ setError('Passwords do not match');
58
+ setIsLoading(false);
59
+ return;
60
+ }
61
+
62
+ try {
63
+ // Try to register via API
64
+ let user;
65
+ let token;
66
+
67
+ try {
68
+ const response = await fetch(`${API_URL}/auth/register`, {
69
+ method: 'POST',
70
+ headers: { 'Content-Type': 'application/json' },
71
+ body: JSON.stringify({
72
+ name: formData.name,
73
+ email: formData.email,
74
+ password: formData.password,
75
+ role: isStudent ? 'student' : 'teacher',
76
+ }),
77
+ });
78
+
79
+ if (response.ok) {
80
+ const data = await response.json();
81
+ user = data.user;
82
+ token = data.token;
83
+ localStorage.setItem('learnflow_token', token);
84
+ } else if (response.status === 400) {
85
+ const data = await response.json();
86
+ setError(data.detail || 'Registration failed');
87
+ setIsLoading(false);
88
+ return;
89
+ } else {
90
+ throw new Error('API not available');
91
+ }
92
+ } catch (apiError) {
93
+ // Fallback to localStorage
94
+ console.log('Using localStorage fallback for registration');
95
+
96
+ user = {
97
+ id: Date.now().toString(),
98
+ name: formData.name,
99
+ email: formData.email,
100
+ role: isStudent ? 'student' : 'teacher',
101
+ createdAt: new Date().toISOString(),
102
+ };
103
+
104
+ const existingUsers = JSON.parse(localStorage.getItem('learnflow_users') || '[]');
105
+ if (existingUsers.find((u: any) => u.email === formData.email)) {
106
+ setError('An account with this email already exists');
107
+ setIsLoading(false);
108
+ return;
109
+ }
110
+
111
+ existingUsers.push({ ...user, password: formData.password });
112
+ localStorage.setItem('learnflow_users', JSON.stringify(existingUsers));
113
+ }
114
+
115
+ // Set current user session
116
+ localStorage.setItem('learnflow_current_user', JSON.stringify(user));
117
+
118
+ // Redirect based on role
119
+ if (isStudent) {
120
+ router.push('/student/dashboard');
121
+ } else {
122
+ router.push('/teacher/dashboard');
123
+ }
124
+ } catch (err) {
125
+ setError('Something went wrong. Please try again.');
126
+ setIsLoading(false);
127
+ }
128
+ };
129
+
130
+ return (
131
+ <div className="min-h-screen bg-cream-50">
132
+ {/* Header */}
133
+ <header className="bg-white/80 backdrop-blur-md border-b border-warmgray-100">
134
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
135
+ <div className="flex justify-between items-center h-16">
136
+ <Link href="/" className="flex items-center">
137
+ <div className="w-10 h-10 bg-gradient-to-br from-teal-500 to-teal-600 rounded-xl flex items-center justify-center shadow-soft">
138
+ <span className="text-white font-bold text-lg">LF</span>
139
+ </div>
140
+ <span className="ml-3 text-xl font-bold text-warmgray-900">LearnFlow</span>
141
+ </Link>
142
+
143
+ <Link
144
+ href="/"
145
+ className="text-warmgray-600 hover:text-teal-600 font-medium text-sm transition-colors flex items-center"
146
+ >
147
+ <svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
148
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
149
+ </svg>
150
+ Back to Home
151
+ </Link>
152
+ </div>
153
+ </div>
154
+ </header>
155
+
156
+ <div className="min-h-[calc(100vh-64px)] flex items-center justify-center py-12 px-4">
157
+ <div className="w-full max-w-md">
158
+ {/* Decorative elements */}
159
+ <div className="absolute top-20 left-10 w-64 h-64 bg-teal-200/20 rounded-full blur-3xl -z-10" />
160
+ <div className="absolute bottom-20 right-10 w-64 h-64 bg-lavender-200/20 rounded-full blur-3xl -z-10" />
161
+
162
+ <div className="bg-white rounded-3xl shadow-soft-lg p-8 md:p-10">
163
+ <div className="text-center mb-8">
164
+ <div className="mx-auto w-16 h-16 bg-gradient-to-br from-teal-400 to-teal-600 rounded-2xl flex items-center justify-center mb-4 shadow-soft">
165
+ <svg className="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
166
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z" />
167
+ </svg>
168
+ </div>
169
+ <h1 className="text-2xl font-bold text-warmgray-900 mb-2">Create Account</h1>
170
+ <p className="text-warmgray-600">Join our learning community today</p>
171
+ </div>
172
+
173
+ {/* Error Message */}
174
+ {error && (
175
+ <div className="mb-6 p-4 bg-coral-50 border border-coral-200 rounded-xl flex items-center text-coral-700">
176
+ <svg className="w-5 h-5 mr-3 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
177
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
178
+ </svg>
179
+ <span className="text-sm">{error}</span>
180
+ </div>
181
+ )}
182
+
183
+ <form onSubmit={handleSubmit} className="space-y-5">
184
+ <div>
185
+ <label htmlFor="name" className="block text-sm font-medium text-warmgray-700 mb-2">
186
+ Full Name
187
+ </label>
188
+ <input
189
+ type="text"
190
+ id="name"
191
+ name="name"
192
+ value={formData.name}
193
+ onChange={handleChange}
194
+ className="input-wellness"
195
+ placeholder="Enter your full name"
196
+ required
197
+ disabled={isLoading}
198
+ />
199
+ </div>
200
+
201
+ <div>
202
+ <label htmlFor="email" className="block text-sm font-medium text-warmgray-700 mb-2">
203
+ Email Address
204
+ </label>
205
+ <input
206
+ type="email"
207
+ id="email"
208
+ name="email"
209
+ value={formData.email}
210
+ onChange={handleChange}
211
+ className="input-wellness"
212
+ placeholder="you@example.com"
213
+ required
214
+ disabled={isLoading}
215
+ />
216
+ </div>
217
+
218
+ <div>
219
+ <label htmlFor="password" className="block text-sm font-medium text-warmgray-700 mb-2">
220
+ Password
221
+ </label>
222
+ <input
223
+ type="password"
224
+ id="password"
225
+ name="password"
226
+ value={formData.password}
227
+ onChange={handleChange}
228
+ className="input-wellness"
229
+ placeholder="At least 6 characters"
230
+ required
231
+ disabled={isLoading}
232
+ />
233
+ </div>
234
+
235
+ <div>
236
+ <label htmlFor="confirmPassword" className="block text-sm font-medium text-warmgray-700 mb-2">
237
+ Confirm Password
238
+ </label>
239
+ <input
240
+ type="password"
241
+ id="confirmPassword"
242
+ name="confirmPassword"
243
+ value={formData.confirmPassword}
244
+ onChange={handleChange}
245
+ className="input-wellness"
246
+ placeholder="Confirm your password"
247
+ required
248
+ disabled={isLoading}
249
+ />
250
+ </div>
251
+
252
+ {/* Role Selection */}
253
+ <div>
254
+ <label className="block text-sm font-medium text-warmgray-700 mb-3">
255
+ I am a
256
+ </label>
257
+ <div className="flex gap-3 p-1.5 bg-warmgray-100 rounded-full">
258
+ <button
259
+ type="button"
260
+ onClick={() => handleRoleChange(true)}
261
+ disabled={isLoading}
262
+ className={`flex-1 px-4 py-2.5 rounded-full text-sm font-medium transition-all duration-300 ${
263
+ isStudent
264
+ ? 'bg-teal-600 text-white shadow-soft'
265
+ : 'text-warmgray-600 hover:text-warmgray-900'
266
+ }`}
267
+ >
268
+ <span className="flex items-center justify-center">
269
+ <svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
270
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
271
+ </svg>
272
+ Student
273
+ </span>
274
+ </button>
275
+ <button
276
+ type="button"
277
+ onClick={() => handleRoleChange(false)}
278
+ disabled={isLoading}
279
+ className={`flex-1 px-4 py-2.5 rounded-full text-sm font-medium transition-all duration-300 ${
280
+ !isStudent
281
+ ? 'bg-lavender-600 text-white shadow-soft'
282
+ : 'text-warmgray-600 hover:text-warmgray-900'
283
+ }`}
284
+ >
285
+ <span className="flex items-center justify-center">
286
+ <svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
287
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
288
+ </svg>
289
+ Teacher
290
+ </span>
291
+ </button>
292
+ </div>
293
+ </div>
294
+
295
+ <button
296
+ type="submit"
297
+ disabled={isLoading}
298
+ className={`w-full py-3 rounded-xl font-medium transition-all duration-300 flex items-center justify-center ${
299
+ isStudent
300
+ ? 'bg-teal-600 hover:bg-teal-700 text-white'
301
+ : 'bg-lavender-600 hover:bg-lavender-700 text-white'
302
+ } ${isLoading ? 'opacity-70 cursor-not-allowed' : ''}`}
303
+ >
304
+ {isLoading ? (
305
+ <>
306
+ <svg className="animate-spin -ml-1 mr-3 h-5 w-5 text-white" fill="none" viewBox="0 0 24 24">
307
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
308
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
309
+ </svg>
310
+ Creating Account...
311
+ </>
312
+ ) : (
313
+ 'Create Account'
314
+ )}
315
+ </button>
316
+ </form>
317
+
318
+ <div className="mt-8 text-center">
319
+ <p className="text-sm text-warmgray-600">
320
+ Already have an account?{' '}
321
+ <Link href="/" className="font-medium text-teal-600 hover:text-teal-700">
322
+ Sign in
323
+ </Link>
324
+ </p>
325
+ </div>
326
+ </div>
327
+ </div>
328
+ </div>
329
+ </div>
330
+ );
331
+ }
app/resources/page.tsx ADDED
@@ -0,0 +1,1272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import Link from 'next/link';
4
+ import { useState } from 'react';
5
+
6
+ type Guide = {
7
+ title: string;
8
+ description: string;
9
+ icon: string;
10
+ difficulty: string;
11
+ readTime: string;
12
+ content: string;
13
+ };
14
+
15
+ type Cheatsheet = {
16
+ title: string;
17
+ icon: string;
18
+ downloads: string;
19
+ content: string;
20
+ };
21
+
22
+ type Video = {
23
+ title: string;
24
+ duration: string;
25
+ views: string;
26
+ thumbnail: string;
27
+ youtubeId: string;
28
+ channel: string;
29
+ };
30
+
31
+ type Tool = {
32
+ name: string;
33
+ description: string;
34
+ url: string;
35
+ icon: string;
36
+ };
37
+
38
+ export default function ResourcesPage() {
39
+ const [activeTab, setActiveTab] = useState('guides');
40
+ const [selectedGuide, setSelectedGuide] = useState<Guide | null>(null);
41
+ const [selectedVideo, setSelectedVideo] = useState<Video | null>(null);
42
+
43
+ const guides: Guide[] = [
44
+ {
45
+ title: 'Python Installation Guide',
46
+ description: 'Step-by-step guide to install Python on Windows, Mac, and Linux.',
47
+ icon: '📥',
48
+ difficulty: 'Beginner',
49
+ readTime: '5 min',
50
+ content: `# Python Installation Guide
51
+
52
+ ## Windows Installation
53
+
54
+ 1. **Download Python**: Visit [python.org](https://python.org) and download the latest version
55
+ 2. **Run Installer**: Double-click the downloaded file
56
+ 3. **Important**: Check "Add Python to PATH" before clicking Install
57
+ 4. **Verify**: Open Command Prompt and type \`python --version\`
58
+
59
+ ## Mac Installation
60
+
61
+ 1. **Using Homebrew** (Recommended):
62
+ \`\`\`bash
63
+ brew install python
64
+ \`\`\`
65
+
66
+ 2. **Or download from python.org**
67
+
68
+ 3. **Verify**: Open Terminal and type \`python3 --version\`
69
+
70
+ ## Linux Installation
71
+
72
+ Most Linux distributions come with Python pre-installed.
73
+
74
+ \`\`\`bash
75
+ # Ubuntu/Debian
76
+ sudo apt update
77
+ sudo apt install python3 python3-pip
78
+
79
+ # Fedora
80
+ sudo dnf install python3 python3-pip
81
+
82
+ # Verify installation
83
+ python3 --version
84
+ \`\`\`
85
+
86
+ ## Next Steps
87
+
88
+ After installation, you can:
89
+ - Run Python scripts: \`python script.py\`
90
+ - Use the interactive shell: \`python\`
91
+ - Install packages: \`pip install package_name\``,
92
+ },
93
+ {
94
+ title: 'Setting Up VS Code for Python',
95
+ description: 'Configure VS Code with the best extensions for Python development.',
96
+ icon: '💻',
97
+ difficulty: 'Beginner',
98
+ readTime: '10 min',
99
+ content: `# Setting Up VS Code for Python
100
+
101
+ ## Step 1: Install VS Code
102
+
103
+ Download from [code.visualstudio.com](https://code.visualstudio.com)
104
+
105
+ ## Step 2: Essential Extensions
106
+
107
+ ### Must-Have Extensions:
108
+
109
+ 1. **Python** (Microsoft)
110
+ - IntelliSense, linting, debugging
111
+ - Search "Python" in Extensions
112
+
113
+ 2. **Pylance**
114
+ - Fast, feature-rich language support
115
+ - Type checking and auto-imports
116
+
117
+ 3. **Python Indent**
118
+ - Correct indentation on Enter
119
+
120
+ ### Recommended Extensions:
121
+
122
+ 4. **autoDocstring**
123
+ - Generate docstrings automatically
124
+
125
+ 5. **Python Test Explorer**
126
+ - Run and debug tests easily
127
+
128
+ ## Step 3: Configure Settings
129
+
130
+ Open Settings (Ctrl+,) and configure:
131
+
132
+ \`\`\`json
133
+ {
134
+ "python.linting.enabled": true,
135
+ "python.linting.pylintEnabled": true,
136
+ "python.formatting.provider": "black",
137
+ "editor.formatOnSave": true
138
+ }
139
+ \`\`\`
140
+
141
+ ## Step 4: Select Python Interpreter
142
+
143
+ 1. Press Ctrl+Shift+P
144
+ 2. Type "Python: Select Interpreter"
145
+ 3. Choose your Python installation
146
+
147
+ ## Pro Tips
148
+
149
+ - Use \`Ctrl+Shift+P\` for command palette
150
+ - \`F5\` to run/debug
151
+ - \`Ctrl+\`\` to open terminal`,
152
+ },
153
+ {
154
+ title: 'Virtual Environments Explained',
155
+ description: 'Learn why and how to use virtual environments in Python projects.',
156
+ icon: '📦',
157
+ difficulty: 'Intermediate',
158
+ readTime: '8 min',
159
+ content: `# Virtual Environments Explained
160
+
161
+ ## Why Use Virtual Environments?
162
+
163
+ - **Isolation**: Each project has its own dependencies
164
+ - **Version Control**: Different projects can use different package versions
165
+ - **Clean System**: Don't pollute global Python installation
166
+ - **Reproducibility**: Share exact dependencies with others
167
+
168
+ ## Creating Virtual Environments
169
+
170
+ ### Using venv (Built-in)
171
+
172
+ \`\`\`bash
173
+ # Create virtual environment
174
+ python -m venv myenv
175
+
176
+ # Activate (Windows)
177
+ myenv\\Scripts\\activate
178
+
179
+ # Activate (Mac/Linux)
180
+ source myenv/bin/activate
181
+
182
+ # Deactivate
183
+ deactivate
184
+ \`\`\`
185
+
186
+ ### Using conda
187
+
188
+ \`\`\`bash
189
+ # Create environment
190
+ conda create --name myenv python=3.11
191
+
192
+ # Activate
193
+ conda activate myenv
194
+
195
+ # Deactivate
196
+ conda deactivate
197
+ \`\`\`
198
+
199
+ ## Managing Dependencies
200
+
201
+ \`\`\`bash
202
+ # Install packages
203
+ pip install requests pandas
204
+
205
+ # Save dependencies
206
+ pip freeze > requirements.txt
207
+
208
+ # Install from requirements
209
+ pip install -r requirements.txt
210
+ \`\`\`
211
+
212
+ ## Best Practices
213
+
214
+ 1. Always use virtual environments for projects
215
+ 2. Keep requirements.txt updated
216
+ 3. Don't commit venv folder to git
217
+ 4. Add venv to .gitignore`,
218
+ },
219
+ {
220
+ title: 'Git for Python Developers',
221
+ description: 'Version control basics every Python developer should know.',
222
+ icon: '🔀',
223
+ difficulty: 'Intermediate',
224
+ readTime: '15 min',
225
+ content: `# Git for Python Developers
226
+
227
+ ## Getting Started
228
+
229
+ \`\`\`bash
230
+ # Configure Git
231
+ git config --global user.name "Your Name"
232
+ git config --global user.email "you@example.com"
233
+
234
+ # Initialize repository
235
+ git init
236
+
237
+ # Clone existing repo
238
+ git clone https://github.com/user/repo.git
239
+ \`\`\`
240
+
241
+ ## Essential Commands
242
+
243
+ \`\`\`bash
244
+ # Check status
245
+ git status
246
+
247
+ # Stage changes
248
+ git add filename.py
249
+ git add . # All files
250
+
251
+ # Commit changes
252
+ git commit -m "Add feature X"
253
+
254
+ # View history
255
+ git log --oneline
256
+ \`\`\`
257
+
258
+ ## Branching
259
+
260
+ \`\`\`bash
261
+ # Create branch
262
+ git branch feature-name
263
+
264
+ # Switch branch
265
+ git checkout feature-name
266
+
267
+ # Create and switch
268
+ git checkout -b feature-name
269
+
270
+ # Merge branch
271
+ git merge feature-name
272
+ \`\`\`
273
+
274
+ ## Python .gitignore
275
+
276
+ \`\`\`
277
+ # Virtual environments
278
+ venv/
279
+ env/
280
+ .env
281
+
282
+ # Python cache
283
+ __pycache__/
284
+ *.pyc
285
+ *.pyo
286
+
287
+ # IDE
288
+ .vscode/
289
+ .idea/
290
+
291
+ # Distribution
292
+ dist/
293
+ build/
294
+ *.egg-info/
295
+ \`\`\`
296
+
297
+ ## Remote Repositories
298
+
299
+ \`\`\`bash
300
+ # Add remote
301
+ git remote add origin URL
302
+
303
+ # Push changes
304
+ git push -u origin main
305
+
306
+ # Pull changes
307
+ git pull origin main
308
+ \`\`\``,
309
+ },
310
+ {
311
+ title: 'Debugging Techniques',
312
+ description: 'Master the art of finding and fixing bugs in your Python code.',
313
+ icon: '🐛',
314
+ difficulty: 'Intermediate',
315
+ readTime: '12 min',
316
+ content: `# Python Debugging Techniques
317
+
318
+ ## 1. Print Debugging
319
+
320
+ \`\`\`python
321
+ def calculate(x, y):
322
+ print(f"DEBUG: x={x}, y={y}") # Add debug prints
323
+ result = x * y
324
+ print(f"DEBUG: result={result}")
325
+ return result
326
+ \`\`\`
327
+
328
+ ## 2. Using the Debugger (pdb)
329
+
330
+ \`\`\`python
331
+ import pdb
332
+
333
+ def buggy_function():
334
+ x = 10
335
+ pdb.set_trace() # Breakpoint
336
+ y = x / 0 # Bug here
337
+ return y
338
+ \`\`\`
339
+
340
+ ### pdb Commands:
341
+ - \`n\` - Next line
342
+ - \`s\` - Step into function
343
+ - \`c\` - Continue
344
+ - \`p variable\` - Print variable
345
+ - \`q\` - Quit
346
+
347
+ ## 3. VS Code Debugging
348
+
349
+ 1. Set breakpoints (click left of line number)
350
+ 2. Press F5 to start debugging
351
+ 3. Use debug controls (step over, step into, continue)
352
+ 4. Watch variables in the sidebar
353
+
354
+ ## 4. Logging
355
+
356
+ \`\`\`python
357
+ import logging
358
+
359
+ logging.basicConfig(level=logging.DEBUG)
360
+ logger = logging.getLogger(__name__)
361
+
362
+ def process_data(data):
363
+ logger.debug(f"Processing: {data}")
364
+ logger.info("Process started")
365
+ logger.warning("Something might be wrong")
366
+ logger.error("An error occurred")
367
+ \`\`\`
368
+
369
+ ## 5. Common Bug Patterns
370
+
371
+ ### Off-by-one errors
372
+ \`\`\`python
373
+ # Wrong
374
+ for i in range(len(items) + 1): # IndexError
375
+
376
+ # Correct
377
+ for i in range(len(items)):
378
+ \`\`\`
379
+
380
+ ### Mutable default arguments
381
+ \`\`\`python
382
+ # Wrong
383
+ def add_item(item, items=[]):
384
+ items.append(item)
385
+ return items
386
+
387
+ # Correct
388
+ def add_item(item, items=None):
389
+ if items is None:
390
+ items = []
391
+ items.append(item)
392
+ return items
393
+ \`\`\``,
394
+ },
395
+ {
396
+ title: 'Python Best Practices',
397
+ description: 'Write clean, maintainable, and Pythonic code.',
398
+ icon: '✨',
399
+ difficulty: 'Advanced',
400
+ readTime: '20 min',
401
+ content: `# Python Best Practices
402
+
403
+ ## 1. Follow PEP 8 Style Guide
404
+
405
+ \`\`\`python
406
+ # Good
407
+ def calculate_total(items):
408
+ total = sum(item.price for item in items)
409
+ return total
410
+
411
+ # Bad
412
+ def CalculateTotal(Items):
413
+ Total=sum(Item.price for Item in Items)
414
+ return Total
415
+ \`\`\`
416
+
417
+ ## 2. Use Type Hints
418
+
419
+ \`\`\`python
420
+ from typing import List, Optional
421
+
422
+ def greet(name: str) -> str:
423
+ return f"Hello, {name}!"
424
+
425
+ def find_user(user_id: int) -> Optional[dict]:
426
+ # Returns user dict or None
427
+ pass
428
+ \`\`\`
429
+
430
+ ## 3. Write Docstrings
431
+
432
+ \`\`\`python
433
+ def calculate_average(numbers: List[float]) -> float:
434
+ """Calculate the average of a list of numbers.
435
+
436
+ Args:
437
+ numbers: A list of numbers to average.
438
+
439
+ Returns:
440
+ The arithmetic mean of the numbers.
441
+
442
+ Raises:
443
+ ValueError: If the list is empty.
444
+ """
445
+ if not numbers:
446
+ raise ValueError("Cannot average empty list")
447
+ return sum(numbers) / len(numbers)
448
+ \`\`\`
449
+
450
+ ## 4. Use Context Managers
451
+
452
+ \`\`\`python
453
+ # Good
454
+ with open('file.txt', 'r') as f:
455
+ content = f.read()
456
+
457
+ # Bad
458
+ f = open('file.txt', 'r')
459
+ content = f.read()
460
+ f.close()
461
+ \`\`\`
462
+
463
+ ## 5. List Comprehensions
464
+
465
+ \`\`\`python
466
+ # Pythonic
467
+ squares = [x**2 for x in range(10)]
468
+ evens = [x for x in numbers if x % 2 == 0]
469
+
470
+ # Less Pythonic
471
+ squares = []
472
+ for x in range(10):
473
+ squares.append(x**2)
474
+ \`\`\`
475
+
476
+ ## 6. Use f-strings
477
+
478
+ \`\`\`python
479
+ name = "Alice"
480
+ age = 30
481
+
482
+ # Good
483
+ message = f"{name} is {age} years old"
484
+
485
+ # Avoid
486
+ message = name + " is " + str(age) + " years old"
487
+ \`\`\`
488
+
489
+ ## 7. Handle Exceptions Properly
490
+
491
+ \`\`\`python
492
+ try:
493
+ result = risky_operation()
494
+ except SpecificError as e:
495
+ logger.error(f"Operation failed: {e}")
496
+ raise
497
+ except Exception as e:
498
+ logger.exception("Unexpected error")
499
+ raise
500
+ \`\`\``,
501
+ },
502
+ ];
503
+
504
+ const cheatsheets: Cheatsheet[] = [
505
+ {
506
+ title: 'Python Syntax Cheatsheet',
507
+ icon: '📝',
508
+ downloads: '12.5k',
509
+ content: `PYTHON SYNTAX CHEATSHEET
510
+ ========================
511
+
512
+ VARIABLES & DATA TYPES
513
+ ----------------------
514
+ x = 10 # Integer
515
+ y = 3.14 # Float
516
+ name = "Python" # String
517
+ is_true = True # Boolean
518
+ items = [1,2,3] # List
519
+ data = {"a": 1} # Dictionary
520
+
521
+ OPERATORS
522
+ ---------
523
+ + Addition - Subtraction
524
+ * Multiplication / Division
525
+ // Floor Division % Modulus
526
+ ** Exponentiation
527
+
528
+ COMPARISON
529
+ ----------
530
+ == Equal != Not Equal
531
+ > Greater < Less
532
+ >= Greater/Equal <= Less/Equal
533
+
534
+ CONTROL FLOW
535
+ ------------
536
+ if condition:
537
+ # code
538
+ elif other:
539
+ # code
540
+ else:
541
+ # code
542
+
543
+ LOOPS
544
+ -----
545
+ for item in items:
546
+ print(item)
547
+
548
+ while condition:
549
+ # code
550
+
551
+ FUNCTIONS
552
+ ---------
553
+ def greet(name):
554
+ return f"Hello, {name}"
555
+
556
+ CLASSES
557
+ -------
558
+ class Person:
559
+ def __init__(self, name):
560
+ self.name = name`,
561
+ },
562
+ {
563
+ title: 'String Methods Reference',
564
+ icon: '🔤',
565
+ downloads: '8.2k',
566
+ content: `STRING METHODS REFERENCE
567
+ ========================
568
+
569
+ CASE METHODS
570
+ ------------
571
+ s.upper() → "HELLO"
572
+ s.lower() → "hello"
573
+ s.capitalize() → "Hello"
574
+ s.title() → "Hello World"
575
+ s.swapcase() → "hELLO"
576
+
577
+ SEARCH METHODS
578
+ --------------
579
+ s.find("x") → index or -1
580
+ s.index("x") → index or error
581
+ s.count("x") → occurrences
582
+ s.startswith("x") → True/False
583
+ s.endswith("x") → True/False
584
+
585
+ MODIFICATION
586
+ ------------
587
+ s.strip() → remove whitespace
588
+ s.lstrip() → remove left whitespace
589
+ s.rstrip() → remove right whitespace
590
+ s.replace("a","b") → replace all
591
+
592
+ SPLIT & JOIN
593
+ ------------
594
+ s.split(",") → ["a","b","c"]
595
+ ",".join(list) → "a,b,c"
596
+ s.splitlines() → split by newline
597
+
598
+ VALIDATION
599
+ ----------
600
+ s.isalpha() → only letters?
601
+ s.isdigit() → only digits?
602
+ s.isalnum() → letters/digits?
603
+ s.isspace() → only whitespace?
604
+ s.isupper() → all uppercase?
605
+ s.islower() → all lowercase?
606
+
607
+ FORMATTING
608
+ ----------
609
+ f"{name}" → f-string
610
+ "{} {}".format() → format method
611
+ s.center(20) → center in width
612
+ s.ljust(20) → left justify
613
+ s.rjust(20) → right justify
614
+ s.zfill(5) → pad with zeros`,
615
+ },
616
+ {
617
+ title: 'List Comprehensions',
618
+ icon: '📋',
619
+ downloads: '9.1k',
620
+ content: `LIST COMPREHENSIONS CHEATSHEET
621
+ ==============================
622
+
623
+ BASIC SYNTAX
624
+ ------------
625
+ [expression for item in iterable]
626
+
627
+ EXAMPLES
628
+ --------
629
+ # Squares
630
+ [x**2 for x in range(10)]
631
+ → [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
632
+
633
+ # With condition (filter)
634
+ [x for x in range(10) if x % 2 == 0]
635
+ → [0, 2, 4, 6, 8]
636
+
637
+ # Transform strings
638
+ [s.upper() for s in ["hello", "world"]]
639
+ → ["HELLO", "WORLD"]
640
+
641
+ # Conditional expression
642
+ ["even" if x%2==0 else "odd" for x in range(5)]
643
+ → ["even", "odd", "even", "odd", "even"]
644
+
645
+ NESTED LOOPS
646
+ ------------
647
+ [(x,y) for x in [1,2] for y in [3,4]]
648
+ → [(1,3), (1,4), (2,3), (2,4)]
649
+
650
+ # Flatten nested list
651
+ [[1,2], [3,4]] → [1, 2, 3, 4]
652
+ [x for sublist in nested for x in sublist]
653
+
654
+ DICT COMPREHENSION
655
+ ------------------
656
+ {k: v for k, v in items}
657
+ {x: x**2 for x in range(5)}
658
+ → {0:0, 1:1, 2:4, 3:9, 4:16}
659
+
660
+ SET COMPREHENSION
661
+ -----------------
662
+ {x**2 for x in range(5)}
663
+ → {0, 1, 4, 9, 16}
664
+
665
+ GENERATOR EXPRESSION
666
+ --------------------
667
+ (x**2 for x in range(10))
668
+ # Memory efficient, lazy evaluation`,
669
+ },
670
+ {
671
+ title: 'Dictionary Operations',
672
+ icon: '📖',
673
+ downloads: '7.8k',
674
+ content: `DICTIONARY OPERATIONS
675
+ =====================
676
+
677
+ CREATING DICTIONARIES
678
+ ---------------------
679
+ d = {}
680
+ d = dict()
681
+ d = {"name": "Alice", "age": 30}
682
+ d = dict(name="Alice", age=30)
683
+
684
+ ACCESSING VALUES
685
+ ----------------
686
+ d["key"] # KeyError if missing
687
+ d.get("key") # None if missing
688
+ d.get("key", default) # default if missing
689
+
690
+ ADDING/UPDATING
691
+ ---------------
692
+ d["key"] = value
693
+ d.update({"a": 1, "b": 2})
694
+ d |= {"new": "data"} # Python 3.9+
695
+
696
+ REMOVING
697
+ --------
698
+ del d["key"]
699
+ d.pop("key") # returns value
700
+ d.pop("key", None) # no error if missing
701
+ d.popitem() # remove last item
702
+ d.clear() # remove all
703
+
704
+ ITERATION
705
+ ---------
706
+ for key in d:
707
+ for key in d.keys():
708
+ for value in d.values():
709
+ for key, value in d.items():
710
+
711
+ USEFUL METHODS
712
+ --------------
713
+ d.keys() # all keys
714
+ d.values() # all values
715
+ d.items() # key-value pairs
716
+ len(d) # number of items
717
+ "key" in d # check existence
718
+ d.copy() # shallow copy
719
+
720
+ MERGING (Python 3.9+)
721
+ ---------------------
722
+ merged = d1 | d2
723
+ d1 |= d2 # in-place
724
+
725
+ DEFAULT VALUES
726
+ --------------
727
+ from collections import defaultdict
728
+ d = defaultdict(list)
729
+ d["key"].append(value)`,
730
+ },
731
+ {
732
+ title: 'File I/O Quick Reference',
733
+ icon: '📁',
734
+ downloads: '6.3k',
735
+ content: `FILE I/O QUICK REFERENCE
736
+ ========================
737
+
738
+ OPENING FILES
739
+ -------------
740
+ f = open("file.txt", mode)
741
+
742
+ MODES
743
+ -----
744
+ "r" - Read (default)
745
+ "w" - Write (overwrites)
746
+ "a" - Append
747
+ "x" - Create (error if exists)
748
+ "b" - Binary mode
749
+ "t" - Text mode (default)
750
+ "+" - Read and write
751
+
752
+ CONTEXT MANAGER (Recommended)
753
+ -----------------------------
754
+ with open("file.txt", "r") as f:
755
+ content = f.read()
756
+ # File automatically closed
757
+
758
+ READING
759
+ -------
760
+ f.read() # entire file
761
+ f.read(n) # n characters
762
+ f.readline() # one line
763
+ f.readlines() # list of lines
764
+
765
+ # Iterate lines
766
+ for line in f:
767
+ print(line)
768
+
769
+ WRITING
770
+ -------
771
+ f.write("text")
772
+ f.writelines(list_of_strings)
773
+
774
+ PRACTICAL EXAMPLES
775
+ ------------------
776
+ # Read entire file
777
+ with open("data.txt") as f:
778
+ content = f.read()
779
+
780
+ # Read lines
781
+ with open("data.txt") as f:
782
+ lines = f.readlines()
783
+
784
+ # Write to file
785
+ with open("output.txt", "w") as f:
786
+ f.write("Hello World")
787
+
788
+ # Append to file
789
+ with open("log.txt", "a") as f:
790
+ f.write("New log entry\\n")
791
+
792
+ JSON FILES
793
+ ----------
794
+ import json
795
+
796
+ # Read JSON
797
+ with open("data.json") as f:
798
+ data = json.load(f)
799
+
800
+ # Write JSON
801
+ with open("data.json", "w") as f:
802
+ json.dump(data, f, indent=2)`,
803
+ },
804
+ {
805
+ title: 'Exception Handling Guide',
806
+ icon: '⚠️',
807
+ downloads: '5.9k',
808
+ content: `EXCEPTION HANDLING GUIDE
809
+ ========================
810
+
811
+ BASIC SYNTAX
812
+ ------------
813
+ try:
814
+ # risky code
815
+ except ExceptionType:
816
+ # handle error
817
+ else:
818
+ # runs if no exception
819
+ finally:
820
+ # always runs
821
+
822
+ COMMON EXCEPTIONS
823
+ -----------------
824
+ ValueError - Wrong value type
825
+ TypeError - Wrong data type
826
+ KeyError - Dict key not found
827
+ IndexError - Index out of range
828
+ FileNotFoundError - File doesn't exist
829
+ ZeroDivisionError - Division by zero
830
+ AttributeError - Attribute not found
831
+ ImportError - Import failed
832
+
833
+ CATCHING EXCEPTIONS
834
+ -------------------
835
+ # Catch specific
836
+ try:
837
+ x = int("abc")
838
+ except ValueError:
839
+ print("Invalid number")
840
+
841
+ # Catch multiple
842
+ except (ValueError, TypeError):
843
+ print("Error occurred")
844
+
845
+ # Get exception info
846
+ except ValueError as e:
847
+ print(f"Error: {e}")
848
+
849
+ # Catch all (avoid when possible)
850
+ except Exception as e:
851
+ print(f"Unexpected: {e}")
852
+
853
+ RAISING EXCEPTIONS
854
+ ------------------
855
+ raise ValueError("Invalid input")
856
+ raise TypeError("Expected string")
857
+
858
+ # Re-raise
859
+ except SomeError:
860
+ logger.error("Failed")
861
+ raise
862
+
863
+ CUSTOM EXCEPTIONS
864
+ -----------------
865
+ class CustomError(Exception):
866
+ def __init__(self, message):
867
+ self.message = message
868
+ super().__init__(message)
869
+
870
+ raise CustomError("Something wrong")
871
+
872
+ BEST PRACTICES
873
+ --------------
874
+ 1. Catch specific exceptions
875
+ 2. Don't use bare except:
876
+ 3. Log exceptions properly
877
+ 4. Clean up in finally
878
+ 5. Fail fast, fail loud`,
879
+ },
880
+ ];
881
+
882
+ const videos: Video[] = [
883
+ {
884
+ title: 'Python in 100 Seconds',
885
+ duration: '2:18',
886
+ views: '3.8M',
887
+ thumbnail: '🎬',
888
+ youtubeId: 'x7X9w_GIm1s',
889
+ channel: 'Fireship',
890
+ },
891
+ {
892
+ title: 'Python Tutorial for Beginners',
893
+ duration: '6:14:07',
894
+ views: '41M',
895
+ thumbnail: '🔄',
896
+ youtubeId: '_uQrJ0TkZlc',
897
+ channel: 'Programming with Mosh',
898
+ },
899
+ {
900
+ title: 'Python OOP Tutorial',
901
+ duration: '1:20:49',
902
+ views: '2.8M',
903
+ thumbnail: '🏗️',
904
+ youtubeId: 'ZDa-Z5JzLYM',
905
+ channel: 'Corey Schafer',
906
+ },
907
+ {
908
+ title: 'Python API Development',
909
+ duration: '19:03:32',
910
+ views: '1.2M',
911
+ thumbnail: '🌐',
912
+ youtubeId: '0sOvCWFmrtA',
913
+ channel: 'freeCodeCamp',
914
+ },
915
+ ];
916
+
917
+ const tools: Tool[] = [
918
+ {
919
+ name: 'Python Official Docs',
920
+ description: 'The official Python documentation',
921
+ url: 'https://docs.python.org/3/',
922
+ icon: '📚',
923
+ },
924
+ {
925
+ name: 'PyPI',
926
+ description: 'Python Package Index - find libraries',
927
+ url: 'https://pypi.org/',
928
+ icon: '📦',
929
+ },
930
+ {
931
+ name: 'Replit',
932
+ description: 'Online Python IDE',
933
+ url: 'https://replit.com/languages/python3',
934
+ icon: '💻',
935
+ },
936
+ {
937
+ name: 'Stack Overflow',
938
+ description: 'Q&A for programmers',
939
+ url: 'https://stackoverflow.com/questions/tagged/python',
940
+ icon: '❓',
941
+ },
942
+ {
943
+ name: 'Real Python',
944
+ description: 'Python tutorials and articles',
945
+ url: 'https://realpython.com/',
946
+ icon: '🐍',
947
+ },
948
+ {
949
+ name: 'Python Tutor',
950
+ description: 'Visualize code execution',
951
+ url: 'https://pythontutor.com/',
952
+ icon: '👁️',
953
+ },
954
+ ];
955
+
956
+ const downloadCheatsheet = (sheet: Cheatsheet) => {
957
+ const blob = new Blob([sheet.content], { type: 'text/plain' });
958
+ const url = URL.createObjectURL(blob);
959
+ const a = document.createElement('a');
960
+ a.href = url;
961
+ a.download = `${sheet.title.replace(/\s+/g, '_')}.txt`;
962
+ document.body.appendChild(a);
963
+ a.click();
964
+ document.body.removeChild(a);
965
+ URL.revokeObjectURL(url);
966
+ };
967
+
968
+ return (
969
+ <div className="min-h-screen bg-gradient-to-b from-cream-50 to-white">
970
+ {/* Header */}
971
+ <header className="bg-white/80 backdrop-blur-md border-b border-warmgray-100 sticky top-0 z-50">
972
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
973
+ <div className="flex items-center justify-between h-16">
974
+ <Link href="/" className="flex items-center space-x-3">
975
+ <div className="w-10 h-10 bg-gradient-to-br from-teal-500 to-teal-600 rounded-xl flex items-center justify-center shadow-soft">
976
+ <span className="text-white font-bold text-lg">L</span>
977
+ </div>
978
+ <span className="text-xl font-bold text-warmgray-900">LearnFlow</span>
979
+ </Link>
980
+
981
+ <nav className="hidden md:flex items-center space-x-1">
982
+ {[
983
+ { name: 'Home', href: '/' },
984
+ { name: 'Courses', href: '/courses' },
985
+ { name: 'About', href: '/about' },
986
+ { name: 'Resources', href: '/resources' },
987
+ { name: 'Contact', href: '/contact' },
988
+ ].map((item) => (
989
+ <Link
990
+ key={item.name}
991
+ href={item.href}
992
+ className={`px-4 py-2 rounded-full text-sm font-medium transition-all duration-200 ${
993
+ item.name === 'Resources'
994
+ ? 'bg-teal-50 text-teal-700'
995
+ : 'text-warmgray-600 hover:text-teal-700 hover:bg-teal-50'
996
+ }`}
997
+ >
998
+ {item.name}
999
+ </Link>
1000
+ ))}
1001
+ </nav>
1002
+
1003
+ <div className="flex items-center space-x-3">
1004
+ <Link href="/register" className="text-warmgray-700 hover:text-teal-700 font-medium text-sm">
1005
+ Sign Up
1006
+ </Link>
1007
+ <Link href="/" className="bg-teal-600 text-white px-5 py-2.5 rounded-full hover:bg-teal-700 transition-all font-medium text-sm">
1008
+ Login
1009
+ </Link>
1010
+ </div>
1011
+ </div>
1012
+ </div>
1013
+ </header>
1014
+
1015
+ {/* Hero Section */}
1016
+ <section className="py-16 px-4">
1017
+ <div className="max-w-4xl mx-auto text-center">
1018
+ <h1 className="text-4xl md:text-5xl font-bold text-warmgray-900 mb-4">
1019
+ Learning <span className="text-teal-600">Resources</span>
1020
+ </h1>
1021
+ <p className="text-lg text-warmgray-600">
1022
+ Free guides, cheatsheets, videos, and tools to accelerate your Python learning journey.
1023
+ </p>
1024
+ </div>
1025
+ </section>
1026
+
1027
+ {/* Tabs */}
1028
+ <section className="px-4 pb-8">
1029
+ <div className="max-w-6xl mx-auto">
1030
+ <div className="flex flex-wrap justify-center gap-2 bg-white rounded-2xl p-2 shadow-soft">
1031
+ {[
1032
+ { id: 'guides', label: 'Guides', icon: '📖' },
1033
+ { id: 'cheatsheets', label: 'Cheatsheets', icon: '📝' },
1034
+ { id: 'videos', label: 'Videos', icon: '🎥' },
1035
+ { id: 'tools', label: 'Tools', icon: '🛠️' },
1036
+ ].map((tab) => (
1037
+ <button
1038
+ key={tab.id}
1039
+ onClick={() => setActiveTab(tab.id)}
1040
+ className={`px-6 py-3 rounded-xl font-medium transition-all duration-200 flex items-center gap-2 ${
1041
+ activeTab === tab.id
1042
+ ? 'bg-teal-600 text-white shadow-soft'
1043
+ : 'text-warmgray-600 hover:bg-teal-50 hover:text-teal-700'
1044
+ }`}
1045
+ >
1046
+ <span>{tab.icon}</span>
1047
+ {tab.label}
1048
+ </button>
1049
+ ))}
1050
+ </div>
1051
+ </div>
1052
+ </section>
1053
+
1054
+ {/* Content */}
1055
+ <section className="px-4 pb-20">
1056
+ <div className="max-w-6xl mx-auto">
1057
+ {activeTab === 'guides' && (
1058
+ <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
1059
+ {guides.map((guide, index) => (
1060
+ <div
1061
+ key={index}
1062
+ onClick={() => setSelectedGuide(guide)}
1063
+ className="bg-white rounded-2xl p-6 shadow-soft hover:shadow-soft-lg transition-all group cursor-pointer"
1064
+ >
1065
+ <div className="text-4xl mb-4">{guide.icon}</div>
1066
+ <div className="flex items-center gap-2 mb-2">
1067
+ <span
1068
+ className={`px-2 py-1 rounded-full text-xs font-medium ${
1069
+ guide.difficulty === 'Beginner'
1070
+ ? 'bg-green-100 text-green-700'
1071
+ : guide.difficulty === 'Intermediate'
1072
+ ? 'bg-yellow-100 text-yellow-700'
1073
+ : 'bg-red-100 text-red-700'
1074
+ }`}
1075
+ >
1076
+ {guide.difficulty}
1077
+ </span>
1078
+ <span className="text-warmgray-400 text-xs">{guide.readTime} read</span>
1079
+ </div>
1080
+ <h3 className="font-semibold text-warmgray-900 mb-2 group-hover:text-teal-600 transition-colors">
1081
+ {guide.title}
1082
+ </h3>
1083
+ <p className="text-sm text-warmgray-600">{guide.description}</p>
1084
+ <div className="mt-4 text-teal-600 text-sm font-medium flex items-center gap-1">
1085
+ Read Guide
1086
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1087
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
1088
+ </svg>
1089
+ </div>
1090
+ </div>
1091
+ ))}
1092
+ </div>
1093
+ )}
1094
+
1095
+ {activeTab === 'cheatsheets' && (
1096
+ <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
1097
+ {cheatsheets.map((sheet, index) => (
1098
+ <div key={index} className="bg-white rounded-2xl p-6 shadow-soft hover:shadow-soft-lg transition-all group">
1099
+ <div className="flex items-center justify-between mb-4">
1100
+ <span className="text-4xl">{sheet.icon}</span>
1101
+ <span className="text-sm text-warmgray-400">{sheet.downloads} downloads</span>
1102
+ </div>
1103
+ <h3 className="font-semibold text-warmgray-900 mb-4 group-hover:text-teal-600 transition-colors">
1104
+ {sheet.title}
1105
+ </h3>
1106
+ <button
1107
+ onClick={() => downloadCheatsheet(sheet)}
1108
+ className="w-full bg-teal-50 text-teal-700 py-2.5 rounded-xl font-medium hover:bg-teal-100 transition-colors flex items-center justify-center gap-2"
1109
+ >
1110
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1111
+ <path
1112
+ strokeLinecap="round"
1113
+ strokeLinejoin="round"
1114
+ strokeWidth={2}
1115
+ d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
1116
+ />
1117
+ </svg>
1118
+ Download Cheatsheet
1119
+ </button>
1120
+ </div>
1121
+ ))}
1122
+ </div>
1123
+ )}
1124
+
1125
+ {activeTab === 'videos' && (
1126
+ <div className="grid md:grid-cols-2 gap-6">
1127
+ {videos.map((video, index) => (
1128
+ <div
1129
+ key={index}
1130
+ onClick={() => setSelectedVideo(video)}
1131
+ className="bg-white rounded-2xl overflow-hidden shadow-soft hover:shadow-soft-lg transition-all group cursor-pointer"
1132
+ >
1133
+ <div className="bg-gradient-to-br from-teal-500 to-sage-500 h-48 flex items-center justify-center relative">
1134
+ <span className="text-6xl">{video.thumbnail}</span>
1135
+ <div className="absolute inset-0 bg-black/20 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
1136
+ <div className="w-16 h-16 bg-white rounded-full flex items-center justify-center">
1137
+ <svg className="w-8 h-8 text-teal-600 ml-1" fill="currentColor" viewBox="0 0 24 24">
1138
+ <path d="M8 5v14l11-7z" />
1139
+ </svg>
1140
+ </div>
1141
+ </div>
1142
+ <span className="absolute bottom-3 right-3 bg-black/70 text-white text-sm px-2 py-1 rounded">
1143
+ {video.duration}
1144
+ </span>
1145
+ </div>
1146
+ <div className="p-5">
1147
+ <h3 className="font-semibold text-warmgray-900 mb-1 group-hover:text-teal-600 transition-colors">
1148
+ {video.title}
1149
+ </h3>
1150
+ <p className="text-sm text-warmgray-500">
1151
+ {video.channel} • {video.views} views
1152
+ </p>
1153
+ </div>
1154
+ </div>
1155
+ ))}
1156
+ </div>
1157
+ )}
1158
+
1159
+ {activeTab === 'tools' && (
1160
+ <div className="grid md:grid-cols-2 gap-6">
1161
+ {tools.map((tool, index) => (
1162
+ <a
1163
+ key={index}
1164
+ href={tool.url}
1165
+ target="_blank"
1166
+ rel="noopener noreferrer"
1167
+ className="bg-white rounded-2xl p-6 shadow-soft hover:shadow-soft-lg transition-all group flex items-center gap-4"
1168
+ >
1169
+ <div className="text-4xl">{tool.icon}</div>
1170
+ <div className="flex-1">
1171
+ <h3 className="font-semibold text-warmgray-900 group-hover:text-teal-600 transition-colors">
1172
+ {tool.name}
1173
+ </h3>
1174
+ <p className="text-sm text-warmgray-600">{tool.description}</p>
1175
+ </div>
1176
+ <svg
1177
+ className="w-5 h-5 text-warmgray-400 group-hover:text-teal-600 transition-colors"
1178
+ fill="none"
1179
+ stroke="currentColor"
1180
+ viewBox="0 0 24 24"
1181
+ >
1182
+ <path
1183
+ strokeLinecap="round"
1184
+ strokeLinejoin="round"
1185
+ strokeWidth={2}
1186
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
1187
+ />
1188
+ </svg>
1189
+ </a>
1190
+ ))}
1191
+ </div>
1192
+ )}
1193
+ </div>
1194
+ </section>
1195
+
1196
+ {/* Guide Modal */}
1197
+ {selectedGuide && (
1198
+ <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4" onClick={() => setSelectedGuide(null)}>
1199
+ <div
1200
+ className="bg-white rounded-2xl max-w-3xl w-full max-h-[90vh] overflow-hidden"
1201
+ onClick={(e) => e.stopPropagation()}
1202
+ >
1203
+ <div className="p-6 border-b border-warmgray-100 flex items-center justify-between">
1204
+ <div className="flex items-center gap-3">
1205
+ <span className="text-3xl">{selectedGuide.icon}</span>
1206
+ <div>
1207
+ <h2 className="text-xl font-bold text-warmgray-900">{selectedGuide.title}</h2>
1208
+ <p className="text-sm text-warmgray-500">{selectedGuide.readTime} read</p>
1209
+ </div>
1210
+ </div>
1211
+ <button
1212
+ onClick={() => setSelectedGuide(null)}
1213
+ className="text-warmgray-400 hover:text-warmgray-600 p-2"
1214
+ >
1215
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1216
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
1217
+ </svg>
1218
+ </button>
1219
+ </div>
1220
+ <div className="p-6 overflow-y-auto max-h-[calc(90vh-100px)]">
1221
+ <pre className="whitespace-pre-wrap font-mono text-sm text-warmgray-700 leading-relaxed">
1222
+ {selectedGuide.content}
1223
+ </pre>
1224
+ </div>
1225
+ </div>
1226
+ </div>
1227
+ )}
1228
+
1229
+ {/* Video Modal */}
1230
+ {selectedVideo && (
1231
+ <div className="fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4" onClick={() => setSelectedVideo(null)}>
1232
+ <div className="w-full max-w-4xl" onClick={(e) => e.stopPropagation()}>
1233
+ <div className="flex justify-between items-center mb-4">
1234
+ <h3 className="text-white font-semibold">{selectedVideo.title}</h3>
1235
+ <button onClick={() => setSelectedVideo(null)} className="text-white hover:text-warmgray-300 p-2">
1236
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
1237
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
1238
+ </svg>
1239
+ </button>
1240
+ </div>
1241
+ <div className="relative pb-[56.25%] h-0">
1242
+ <iframe
1243
+ className="absolute top-0 left-0 w-full h-full rounded-xl"
1244
+ src={`https://www.youtube.com/embed/${selectedVideo.youtubeId}?autoplay=1`}
1245
+ title={selectedVideo.title}
1246
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
1247
+ allowFullScreen
1248
+ />
1249
+ </div>
1250
+ <p className="text-warmgray-400 mt-3 text-sm">
1251
+ {selectedVideo.channel} • {selectedVideo.views} views
1252
+ </p>
1253
+ </div>
1254
+ </div>
1255
+ )}
1256
+
1257
+ {/* CTA */}
1258
+ <section className="py-16 px-4 bg-gradient-to-r from-teal-600 to-teal-700">
1259
+ <div className="max-w-4xl mx-auto text-center text-white">
1260
+ <h2 className="text-3xl font-bold mb-4">Want More Resources?</h2>
1261
+ <p className="text-teal-100 mb-8">Sign up for free and get access to exclusive learning materials.</p>
1262
+ <Link
1263
+ href="/register"
1264
+ className="inline-block bg-white text-teal-700 px-8 py-3 rounded-full font-semibold hover:bg-cream-50 transition-colors shadow-lg"
1265
+ >
1266
+ Get Started Free
1267
+ </Link>
1268
+ </div>
1269
+ </section>
1270
+ </div>
1271
+ );
1272
+ }
app/student/chat/page.tsx ADDED
@@ -0,0 +1,420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useRef } from 'react';
4
+ import { useRouter } from 'next/navigation';
5
+ import Link from 'next/link';
6
+
7
+ const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
8
+
9
+ type Message = {
10
+ id: number;
11
+ role: 'user' | 'assistant';
12
+ content: string;
13
+ timestamp: Date;
14
+ };
15
+
16
+ type User = {
17
+ id: string;
18
+ name: string;
19
+ email: string;
20
+ role: string;
21
+ };
22
+
23
+ export default function ChatPage() {
24
+ const router = useRouter();
25
+ const [user, setUser] = useState<User | null>(null);
26
+ const [isLoading, setIsLoading] = useState(true);
27
+ const [messages, setMessages] = useState<Message[]>([
28
+ {
29
+ id: 1,
30
+ role: 'assistant',
31
+ content: "Hello! I'm your Python AI tutor. I'm here to help you learn Python programming. You can ask me about:\n\n- Python syntax and concepts\n- Code explanations\n- Debugging help\n- Best practices\n- Exercise guidance\n\nWhat would you like to learn today?",
32
+ timestamp: new Date()
33
+ }
34
+ ]);
35
+ const [inputMessage, setInputMessage] = useState('');
36
+ const [isSending, setIsSending] = useState(false);
37
+ const messagesEndRef = useRef<HTMLDivElement>(null);
38
+
39
+ const suggestedQuestions = [
40
+ "How do I create a for loop?",
41
+ "Explain list comprehensions",
42
+ "What are Python functions?",
43
+ "How do I handle errors?",
44
+ ];
45
+
46
+ useEffect(() => {
47
+ const currentUser = localStorage.getItem('learnflow_current_user');
48
+ if (!currentUser) {
49
+ router.push('/');
50
+ return;
51
+ }
52
+
53
+ const parsedUser = JSON.parse(currentUser);
54
+ if (parsedUser.role !== 'student') {
55
+ router.push('/teacher/dashboard');
56
+ return;
57
+ }
58
+
59
+ setUser(parsedUser);
60
+ setIsLoading(false);
61
+ }, [router]);
62
+
63
+ useEffect(() => {
64
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
65
+ }, [messages]);
66
+
67
+ const generateResponse = (question: string): string => {
68
+ const lowerQuestion = question.toLowerCase();
69
+
70
+ if (lowerQuestion.includes('for loop') || lowerQuestion.includes('loop')) {
71
+ return `Great question! A for loop in Python is used to iterate over sequences like lists, strings, or ranges.
72
+
73
+ Here's the basic syntax:
74
+
75
+ \`\`\`python
76
+ # Iterating over a list
77
+ fruits = ['apple', 'banana', 'cherry']
78
+ for fruit in fruits:
79
+ print(fruit)
80
+
81
+ # Using range
82
+ for i in range(5):
83
+ print(i) # Prints 0, 1, 2, 3, 4
84
+
85
+ # Using range with start, stop, step
86
+ for i in range(0, 10, 2):
87
+ print(i) # Prints 0, 2, 4, 6, 8
88
+ \`\`\`
89
+
90
+ Key points:
91
+ - No need for index counters like in other languages
92
+ - The indented block is the loop body
93
+ - Use \`break\` to exit early, \`continue\` to skip iterations
94
+
95
+ Would you like me to explain more or show different examples?`;
96
+ }
97
+
98
+ if (lowerQuestion.includes('list comprehension')) {
99
+ return `List comprehensions are a concise way to create lists in Python!
100
+
101
+ Basic syntax: \`[expression for item in iterable]\`
102
+
103
+ Examples:
104
+
105
+ \`\`\`python
106
+ # Create a list of squares
107
+ squares = [x**2 for x in range(10)]
108
+ # Result: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
109
+
110
+ # With condition (filtering)
111
+ evens = [x for x in range(20) if x % 2 == 0]
112
+ # Result: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
113
+
114
+ # String manipulation
115
+ words = ['hello', 'world']
116
+ upper_words = [word.upper() for word in words]
117
+ # Result: ['HELLO', 'WORLD']
118
+ \`\`\`
119
+
120
+ Benefits:
121
+ - More readable than traditional loops
122
+ - Usually faster
123
+ - Can include conditions for filtering
124
+
125
+ Would you like to practice with some exercises?`;
126
+ }
127
+
128
+ if (lowerQuestion.includes('function')) {
129
+ return `Functions in Python are reusable blocks of code that perform specific tasks.
130
+
131
+ Basic syntax:
132
+
133
+ \`\`\`python
134
+ # Simple function
135
+ def greet(name):
136
+ return f"Hello, {name}!"
137
+
138
+ # Function with default parameter
139
+ def greet_with_title(name, title="Mr."):
140
+ return f"Hello, {title} {name}!"
141
+
142
+ # Function with multiple return values
143
+ def get_stats(numbers):
144
+ return min(numbers), max(numbers), sum(numbers)/len(numbers)
145
+
146
+ # Using the functions
147
+ print(greet("Alice")) # Hello, Alice!
148
+ print(greet_with_title("Smith")) # Hello, Mr. Smith!
149
+ minimum, maximum, average = get_stats([1, 2, 3, 4, 5])
150
+ \`\`\`
151
+
152
+ Key concepts:
153
+ - \`def\` keyword defines a function
154
+ - Parameters go in parentheses
155
+ - \`return\` sends values back
156
+ - Functions can have default parameters
157
+ - *args and **kwargs for flexible arguments
158
+
159
+ Want me to explain any of these in more detail?`;
160
+ }
161
+
162
+ if (lowerQuestion.includes('error') || lowerQuestion.includes('exception') || lowerQuestion.includes('debug')) {
163
+ return `Error handling in Python uses try/except blocks to gracefully handle exceptions.
164
+
165
+ \`\`\`python
166
+ # Basic try/except
167
+ try:
168
+ result = 10 / 0
169
+ except ZeroDivisionError:
170
+ print("Cannot divide by zero!")
171
+
172
+ # Multiple exceptions
173
+ try:
174
+ value = int("not a number")
175
+ except ValueError:
176
+ print("Invalid number format")
177
+ except TypeError:
178
+ print("Type error occurred")
179
+
180
+ # Using else and finally
181
+ try:
182
+ file = open("data.txt", "r")
183
+ data = file.read()
184
+ except FileNotFoundError:
185
+ print("File not found!")
186
+ else:
187
+ print("File read successfully")
188
+ finally:
189
+ file.close() # Always executes
190
+
191
+ # Raising exceptions
192
+ def validate_age(age):
193
+ if age < 0:
194
+ raise ValueError("Age cannot be negative")
195
+ return age
196
+ \`\`\`
197
+
198
+ Common exceptions:
199
+ - \`ValueError\` - Wrong value type
200
+ - \`TypeError\` - Wrong data type
201
+ - \`KeyError\` - Missing dictionary key
202
+ - \`IndexError\` - Index out of range
203
+ - \`FileNotFoundError\` - File doesn't exist
204
+
205
+ Need help debugging a specific error?`;
206
+ }
207
+
208
+ // Default response
209
+ return `That's a great question about "${question}"!
210
+
211
+ As your AI Python tutor, I can help you understand this concept better. Here are some suggestions:
212
+
213
+ 1. **Try it yourself**: Open the Learn page and experiment with code
214
+ 2. **Take a quiz**: Test your knowledge on this topic
215
+ 3. **Ask follow-up questions**: I'm here to help clarify anything
216
+
217
+ Would you like me to:
218
+ - Provide a code example?
219
+ - Explain the underlying concept?
220
+ - Give you a practice exercise?
221
+
222
+ Feel free to ask more specific questions!`;
223
+ };
224
+
225
+ const handleSendMessage = async () => {
226
+ if (!inputMessage.trim() || isSending) return;
227
+
228
+ const userMessage: Message = {
229
+ id: messages.length + 1,
230
+ role: 'user',
231
+ content: inputMessage.trim(),
232
+ timestamp: new Date()
233
+ };
234
+
235
+ setMessages(prev => [...prev, userMessage]);
236
+ setInputMessage('');
237
+ setIsSending(true);
238
+
239
+ let responseText = '';
240
+
241
+ // Try to call the real API
242
+ try {
243
+ const token = localStorage.getItem('learnflow_token');
244
+ const response = await fetch(`${API_URL}/chat`, {
245
+ method: 'POST',
246
+ headers: {
247
+ 'Content-Type': 'application/json',
248
+ ...(token && { 'Authorization': `Bearer ${token}` }),
249
+ },
250
+ body: JSON.stringify({
251
+ messages: [...messages, userMessage].map(m => ({
252
+ role: m.role,
253
+ content: m.content
254
+ })),
255
+ user_id: user?.id || 'anonymous',
256
+ }),
257
+ });
258
+
259
+ if (response.ok) {
260
+ const data = await response.json();
261
+ responseText = data.response;
262
+ } else {
263
+ // Fallback to simulated response
264
+ responseText = generateResponse(userMessage.content);
265
+ }
266
+ } catch (error) {
267
+ // API not available, use simulated response
268
+ console.log('Using simulated response (API not available)');
269
+ responseText = generateResponse(userMessage.content);
270
+ }
271
+
272
+ const assistantMessage: Message = {
273
+ id: messages.length + 2,
274
+ role: 'assistant',
275
+ content: responseText,
276
+ timestamp: new Date()
277
+ };
278
+
279
+ setMessages(prev => [...prev, assistantMessage]);
280
+ setIsSending(false);
281
+ };
282
+
283
+ const handleSuggestedQuestion = (question: string) => {
284
+ setInputMessage(question);
285
+ };
286
+
287
+ if (isLoading) {
288
+ return (
289
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex items-center justify-center">
290
+ <div className="text-center">
291
+ <div className="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
292
+ <p className="text-gray-600">Loading chat...</p>
293
+ </div>
294
+ </div>
295
+ );
296
+ }
297
+
298
+ return (
299
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex flex-col">
300
+ <header className="bg-white/80 backdrop-blur-md shadow-lg border-b border-white/20 sticky top-0 z-10">
301
+ <div className="max-w-4xl mx-auto px-4 py-4 sm:px-6 lg:px-8">
302
+ <div className="flex items-center justify-between">
303
+ <Link href="/student/dashboard" className="flex items-center space-x-3">
304
+ <div className="w-10 h-10 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
305
+ <span className="text-white font-bold text-sm">LF</span>
306
+ </div>
307
+ <div>
308
+ <span className="text-xl font-bold text-gray-900">AI Python Tutor</span>
309
+ <div className="flex items-center text-sm text-green-600">
310
+ <span className="w-2 h-2 bg-green-500 rounded-full mr-2"></span>
311
+ Online
312
+ </div>
313
+ </div>
314
+ </Link>
315
+ <Link
316
+ href="/student/dashboard"
317
+ className="text-gray-600 hover:text-gray-800 font-medium flex items-center"
318
+ >
319
+ <svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
320
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
321
+ </svg>
322
+ Back
323
+ </Link>
324
+ </div>
325
+ </div>
326
+ </header>
327
+
328
+ <main className="flex-1 max-w-4xl w-full mx-auto px-4 py-6 flex flex-col">
329
+ {/* Suggested Questions */}
330
+ {messages.length <= 1 && (
331
+ <div className="mb-4">
332
+ <p className="text-sm text-gray-500 mb-2">Try asking:</p>
333
+ <div className="flex flex-wrap gap-2">
334
+ {suggestedQuestions.map((question, index) => (
335
+ <button
336
+ key={index}
337
+ onClick={() => handleSuggestedQuestion(question)}
338
+ className="px-3 py-1.5 bg-white rounded-full text-sm text-blue-600 hover:bg-blue-50 border border-blue-200 transition-colors"
339
+ >
340
+ {question}
341
+ </button>
342
+ ))}
343
+ </div>
344
+ </div>
345
+ )}
346
+
347
+ {/* Messages */}
348
+ <div className="flex-1 overflow-y-auto space-y-4 mb-4">
349
+ {messages.map((message) => (
350
+ <div
351
+ key={message.id}
352
+ className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
353
+ >
354
+ <div
355
+ className={`max-w-[80%] p-4 rounded-2xl ${
356
+ message.role === 'user'
357
+ ? 'bg-gradient-to-r from-blue-500 to-purple-600 text-white'
358
+ : 'bg-white shadow-lg text-gray-800'
359
+ }`}
360
+ >
361
+ {message.role === 'assistant' && (
362
+ <div className="flex items-center mb-2">
363
+ <div className="w-6 h-6 bg-gradient-to-r from-green-400 to-blue-500 rounded-full flex items-center justify-center mr-2">
364
+ <svg className="w-3 h-3 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
365
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
366
+ </svg>
367
+ </div>
368
+ <span className="text-xs text-gray-500">AI Tutor</span>
369
+ </div>
370
+ )}
371
+ <div className="whitespace-pre-wrap text-sm">{message.content}</div>
372
+ <div className={`text-xs mt-2 ${message.role === 'user' ? 'text-blue-200' : 'text-gray-400'}`}>
373
+ {message.timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
374
+ </div>
375
+ </div>
376
+ </div>
377
+ ))}
378
+
379
+ {isSending && (
380
+ <div className="flex justify-start">
381
+ <div className="bg-white shadow-lg p-4 rounded-2xl">
382
+ <div className="flex items-center space-x-2">
383
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0ms' }}></div>
384
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '150ms' }}></div>
385
+ <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '300ms' }}></div>
386
+ </div>
387
+ </div>
388
+ </div>
389
+ )}
390
+
391
+ <div ref={messagesEndRef} />
392
+ </div>
393
+
394
+ {/* Input */}
395
+ <div className="bg-white rounded-2xl shadow-lg p-4">
396
+ <div className="flex items-center space-x-4">
397
+ <input
398
+ type="text"
399
+ value={inputMessage}
400
+ onChange={(e) => setInputMessage(e.target.value)}
401
+ onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
402
+ placeholder="Ask me anything about Python..."
403
+ disabled={isSending}
404
+ className="flex-1 bg-gray-100 rounded-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50"
405
+ />
406
+ <button
407
+ onClick={handleSendMessage}
408
+ disabled={!inputMessage.trim() || isSending}
409
+ className="bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 disabled:opacity-50 disabled:cursor-not-allowed text-white p-3 rounded-xl transition-all"
410
+ >
411
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
412
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
413
+ </svg>
414
+ </button>
415
+ </div>
416
+ </div>
417
+ </main>
418
+ </div>
419
+ );
420
+ }
app/student/dashboard/page.tsx ADDED
@@ -0,0 +1,477 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import Link from 'next/link';
5
+ import { useRouter } from 'next/navigation';
6
+
7
+ type Module = {
8
+ id: string;
9
+ name: string;
10
+ description: string;
11
+ masteryLevel: number; // 0-100
12
+ progress: number; // 0-100
13
+ status: 'locked' | 'in-progress' | 'completed';
14
+ };
15
+
16
+ type User = {
17
+ id: string;
18
+ name: string;
19
+ email: string;
20
+ role: string;
21
+ };
22
+
23
+ export default function StudentDashboard() {
24
+ const router = useRouter();
25
+ const [user, setUser] = useState<User | null>(null);
26
+ const [isLoading, setIsLoading] = useState(true);
27
+
28
+ const [modules, setModules] = useState<Module[]>([
29
+ {
30
+ id: 'mod1',
31
+ name: 'Python Basics',
32
+ description: 'Variables, data types, operators, input/output',
33
+ masteryLevel: 85,
34
+ progress: 100,
35
+ status: 'completed'
36
+ },
37
+ {
38
+ id: 'mod2',
39
+ name: 'Control Flow',
40
+ description: 'Conditional statements, loops, break/continue',
41
+ masteryLevel: 65,
42
+ progress: 75,
43
+ status: 'in-progress'
44
+ },
45
+ {
46
+ id: 'mod3',
47
+ name: 'Functions',
48
+ description: 'Defining functions, parameters, return values',
49
+ masteryLevel: 30,
50
+ progress: 40,
51
+ status: 'in-progress'
52
+ },
53
+ {
54
+ id: 'mod4',
55
+ name: 'Data Structures',
56
+ description: 'Lists, tuples, dictionaries, sets',
57
+ masteryLevel: 0,
58
+ progress: 0,
59
+ status: 'locked'
60
+ },
61
+ {
62
+ id: 'mod5',
63
+ name: 'Object-Oriented Programming',
64
+ description: 'Classes, objects, inheritance, polymorphism',
65
+ masteryLevel: 0,
66
+ progress: 0,
67
+ status: 'locked'
68
+ },
69
+ {
70
+ id: 'mod6',
71
+ name: 'File Operations',
72
+ description: 'Reading/writing files, CSV, JSON',
73
+ masteryLevel: 0,
74
+ progress: 0,
75
+ status: 'locked'
76
+ },
77
+ {
78
+ id: 'mod7',
79
+ name: 'Error Handling',
80
+ description: 'Try/except blocks, exception types, debugging',
81
+ masteryLevel: 0,
82
+ progress: 0,
83
+ status: 'locked'
84
+ },
85
+ {
86
+ id: 'mod8',
87
+ name: 'Libraries & APIs',
88
+ description: 'Installing packages, using APIs, virtual environments',
89
+ masteryLevel: 0,
90
+ progress: 0,
91
+ status: 'locked'
92
+ }
93
+ ]);
94
+
95
+ const [recentActivities, setRecentActivities] = useState([
96
+ { id: 1, activity: 'Completed "Loops in Python" quiz', timestamp: '2026-01-15 14:30', score: 85 },
97
+ { id: 2, activity: 'Submitted "Function Practice" exercise', timestamp: '2026-01-15 12:15', result: 'Passed' },
98
+ { id: 3, activity: 'Asked "How do I use list comprehensions?"', timestamp: '2026-01-15 10:45', response: 'Explained' }
99
+ ]);
100
+
101
+ useEffect(() => {
102
+ // Check if user is logged in
103
+ const currentUser = localStorage.getItem('learnflow_current_user');
104
+ if (!currentUser) {
105
+ router.push('/');
106
+ return;
107
+ }
108
+
109
+ const parsedUser = JSON.parse(currentUser);
110
+ if (parsedUser.role !== 'student') {
111
+ router.push('/teacher/dashboard');
112
+ return;
113
+ }
114
+
115
+ setUser(parsedUser);
116
+ setIsLoading(false);
117
+ }, [router]);
118
+
119
+ const handleLogout = () => {
120
+ localStorage.removeItem('learnflow_current_user');
121
+ router.push('/');
122
+ };
123
+
124
+ if (isLoading) {
125
+ return (
126
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex items-center justify-center">
127
+ <div className="text-center">
128
+ <div className="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
129
+ <p className="text-gray-600">Loading dashboard...</p>
130
+ </div>
131
+ </div>
132
+ );
133
+ }
134
+
135
+ return (
136
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
137
+ {/* Animated background */}
138
+ <div className="absolute inset-0 overflow-hidden">
139
+ <div className="absolute -top-40 -right-40 w-80 h-80 bg-purple-200 rounded-full mix-blend-multiply filter blur-xl opacity-30 animate-pulse"></div>
140
+ <div className="absolute -bottom-40 -left-40 w-80 h-80 bg-blue-200 rounded-full mix-blend-multiply filter blur-xl opacity-30 animate-pulse animation-delay-2000"></div>
141
+ </div>
142
+
143
+ <div className="relative">
144
+ <header className="bg-white/80 backdrop-blur-md shadow-lg border-b border-white/20 sticky top-0 z-10">
145
+ <div className="max-w-7xl mx-auto px-4 py-4 sm:px-6 lg:px-8 flex justify-between items-center">
146
+ <div className="flex items-center space-x-4">
147
+ <div className="w-10 h-10 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
148
+ <span className="text-white font-bold text-sm">LF</span>
149
+ </div>
150
+ <h1 className="text-2xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
151
+ LearnFlow Dashboard
152
+ </h1>
153
+ </div>
154
+
155
+ <div className="flex items-center space-x-4">
156
+ <div className="flex items-center space-x-3 bg-gray-100/50 rounded-full px-4 py-2">
157
+ <div className="w-8 h-8 bg-gradient-to-r from-green-400 to-blue-500 rounded-full flex items-center justify-center">
158
+ <span className="text-white text-sm font-semibold">{user?.name?.charAt(0).toUpperCase() || 'U'}</span>
159
+ </div>
160
+ <span className="text-gray-700 font-medium">{user?.name?.split(' ')[0] || 'User'}</span>
161
+ </div>
162
+ <button
163
+ onClick={handleLogout}
164
+ className="bg-gradient-to-r from-red-500 to-pink-600 hover:from-red-600 hover:to-pink-700 text-white px-4 py-2 rounded-lg transition-all duration-300 transform hover:scale-105 shadow-md"
165
+ >
166
+ Logout
167
+ </button>
168
+ </div>
169
+ </div>
170
+ </header>
171
+
172
+ <main className="max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8">
173
+ <div className="mb-8">
174
+ <h2 className="text-3xl font-bold text-gray-800 mb-2">Welcome back, {user?.name?.split(' ')[0] || 'Student'}!</h2>
175
+ <p className="text-gray-600">Continue your Python learning journey where you left off</p>
176
+ </div>
177
+
178
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
179
+ {/* Progress Overview */}
180
+ <div className="lg:col-span-2">
181
+ <div className="bg-white/70 backdrop-blur-sm rounded-2xl shadow-xl border border-white/20 p-6 mb-8">
182
+ <h2 className="text-2xl font-bold text-gray-800 mb-6 flex items-center">
183
+ <svg className="w-6 h-6 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
184
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
185
+ </svg>
186
+ Your Learning Progress
187
+ </h2>
188
+
189
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
190
+ <div className="bg-gradient-to-br from-blue-100 to-blue-200 p-5 rounded-xl shadow-md border border-white/50">
191
+ <div className="flex items-center justify-between">
192
+ <div>
193
+ <p className="text-sm font-semibold text-blue-800">Overall Mastery</p>
194
+ <p className="text-3xl font-bold text-blue-600 mt-1">72%</p>
195
+ </div>
196
+ <div className="w-12 h-12 bg-blue-500/20 rounded-full flex items-center justify-center">
197
+ <svg className="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
198
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
199
+ </svg>
200
+ </div>
201
+ </div>
202
+ </div>
203
+
204
+ <div className="bg-gradient-to-br from-green-100 to-green-200 p-5 rounded-xl shadow-md border border-white/50">
205
+ <div className="flex items-center justify-between">
206
+ <div>
207
+ <p className="text-sm font-semibold text-green-800">Modules Completed</p>
208
+ <p className="text-3xl font-bold text-green-600 mt-1">2/8</p>
209
+ </div>
210
+ <div className="w-12 h-12 bg-green-500/20 rounded-full flex items-center justify-center">
211
+ <svg className="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
212
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
213
+ </svg>
214
+ </div>
215
+ </div>
216
+ </div>
217
+
218
+ <div className="bg-gradient-to-br from-yellow-100 to-yellow-200 p-5 rounded-xl shadow-md border border-white/50">
219
+ <div className="flex items-center justify-between">
220
+ <div>
221
+ <p className="text-sm font-semibold text-yellow-800">Current Streak</p>
222
+ <p className="text-3xl font-bold text-yellow-600 mt-1">5 days</p>
223
+ </div>
224
+ <div className="w-12 h-12 bg-yellow-500/20 rounded-full flex items-center justify-center">
225
+ <svg className="w-6 h-6 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
226
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 18.657A8 8 0 016.343 7.343S7 9 9 10c0-2 .5-5 2.986-7C14 5 16.09 5.777 17.656 7.343A7.975 7.975 0 0120 13a7.975 7.975 0 01-2.343 5.657z" />
227
+ </svg>
228
+ </div>
229
+ </div>
230
+ </div>
231
+
232
+ <div className="bg-gradient-to-br from-purple-100 to-purple-200 p-5 rounded-xl shadow-md border border-white/50">
233
+ <div className="flex items-center justify-between">
234
+ <div>
235
+ <p className="text-sm font-semibold text-purple-800">Hours Learned</p>
236
+ <p className="text-3xl font-bold text-purple-600 mt-1">24</p>
237
+ </div>
238
+ <div className="w-12 h-12 bg-purple-500/20 rounded-full flex items-center justify-center">
239
+ <svg className="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
240
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
241
+ </svg>
242
+ </div>
243
+ </div>
244
+ </div>
245
+ </div>
246
+
247
+ <h3 className="text-xl font-semibold text-gray-800 mb-4 flex items-center">
248
+ <svg className="w-5 h-5 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
249
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
250
+ </svg>
251
+ Learning Modules
252
+ </h3>
253
+
254
+ <div className="space-y-4">
255
+ {modules.map((module) => (
256
+ <div
257
+ key={module.id}
258
+ className={`bg-white/50 backdrop-blur-sm rounded-xl p-5 border transition-all duration-300 hover:shadow-lg ${
259
+ module.status === 'locked'
260
+ ? 'opacity-60 border-gray-200'
261
+ : module.status === 'in-progress'
262
+ ? 'border-blue-200 shadow-md'
263
+ : 'border-green-200 shadow-md'
264
+ }`}
265
+ >
266
+ <div className="flex justify-between items-start">
267
+ <div className="flex-1">
268
+ <div className="flex items-center mb-2">
269
+ <h4 className="font-bold text-lg text-gray-800">{module.name}</h4>
270
+ {module.status === 'completed' && (
271
+ <span className="ml-3 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
272
+ <svg className="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
273
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
274
+ </svg>
275
+ Completed
276
+ </span>
277
+ )}
278
+ {module.status === 'in-progress' && (
279
+ <span className="ml-3 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
280
+ <svg className="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
281
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
282
+ </svg>
283
+ In Progress
284
+ </span>
285
+ )}
286
+ </div>
287
+ <p className="text-gray-600 text-sm mb-3">{module.description}</p>
288
+
289
+ <div className="flex items-center justify-between mb-2">
290
+ <span className="text-sm font-medium text-gray-700">Progress: {module.progress}%</span>
291
+ <span className="text-sm font-medium text-gray-700">Mastery: {module.masteryLevel}%</span>
292
+ </div>
293
+
294
+ <div className="w-full bg-gray-200 rounded-full h-2.5 mb-2">
295
+ <div
296
+ className={`h-2.5 rounded-full ${
297
+ module.status === 'completed' ? 'bg-green-500' :
298
+ module.status === 'in-progress' ? 'bg-blue-500' : 'bg-gray-400'
299
+ }`}
300
+ style={{ width: `${module.progress}%` }}
301
+ ></div>
302
+ </div>
303
+ </div>
304
+
305
+ <Link
306
+ href={`/student/learn?module=${module.id}`}
307
+ className={`ml-4 px-4 py-2 rounded-lg font-medium transition-all duration-300 transform hover:scale-105 ${
308
+ module.status === 'locked'
309
+ ? 'bg-gray-300 text-gray-500 cursor-not-allowed'
310
+ : module.status === 'completed'
311
+ ? 'bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 text-white shadow-md'
312
+ : module.status === 'in-progress'
313
+ ? 'bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white shadow-md'
314
+ : 'bg-gradient-to-r from-purple-500 to-purple-600 hover:from-purple-600 hover:to-purple-700 text-white shadow-md'
315
+ }`}
316
+ prefetch={false}
317
+ >
318
+ {module.status === 'completed' ? 'Review' :
319
+ module.status === 'in-progress' ? 'Continue' : 'Start'}
320
+ </Link>
321
+ </div>
322
+
323
+ <div className="mt-3 flex items-center">
324
+ <span className={`text-xs px-3 py-1 rounded-full font-medium ${
325
+ module.masteryLevel >= 90 ? 'bg-gradient-to-r from-blue-100 to-blue-200 text-blue-800' :
326
+ module.masteryLevel >= 70 ? 'bg-gradient-to-r from-green-100 to-green-200 text-green-800' :
327
+ module.masteryLevel >= 40 ? 'bg-gradient-to-r from-yellow-100 to-yellow-200 text-yellow-800' :
328
+ 'bg-gradient-to-r from-red-100 to-red-200 text-red-800'
329
+ }`}>
330
+ {module.masteryLevel >= 90 ? '⭐ Mastered' :
331
+ module.masteryLevel >= 70 ? '💪 Proficient' :
332
+ module.masteryLevel >= 40 ? '📚 Learning' : '🌱 Beginner'}
333
+ </span>
334
+ </div>
335
+ </div>
336
+ ))}
337
+ </div>
338
+ </div>
339
+ </div>
340
+
341
+ {/* Sidebar */}
342
+ <div className="space-y-6">
343
+ {/* Recent Activity */}
344
+ <div className="bg-white/70 backdrop-blur-sm rounded-2xl shadow-xl border border-white/20 p-6">
345
+ <h3 className="text-xl font-bold text-gray-800 mb-4 flex items-center">
346
+ <svg className="w-5 h-5 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
347
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
348
+ </svg>
349
+ Recent Activity
350
+ </h3>
351
+ <ul className="space-y-4">
352
+ {recentActivities.map((activity) => (
353
+ <li key={activity.id} className="border-b border-gray-100 pb-4 last:border-0 last:pb-0">
354
+ <div className="flex items-start">
355
+ <div className="flex-shrink-0 mt-1">
356
+ <div className="w-8 h-8 bg-gradient-to-r from-blue-100 to-purple-100 rounded-full flex items-center justify-center">
357
+ <svg className="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
358
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
359
+ </svg>
360
+ </div>
361
+ </div>
362
+ <div className="ml-3">
363
+ <p className="text-sm font-medium text-gray-800">{activity.activity}</p>
364
+ <p className="text-xs text-gray-500 mt-1">{activity.timestamp}</p>
365
+ {activity.score && (
366
+ <span className="inline-block mt-1 px-2 py-1 text-xs bg-green-100 text-green-800 rounded-full">
367
+ Score: {activity.score}%
368
+ </span>
369
+ )}
370
+ {activity.result && (
371
+ <span className="inline-block mt-1 px-2 py-1 text-xs bg-blue-100 text-blue-800 rounded-full">
372
+ {activity.result}
373
+ </span>
374
+ )}
375
+ </div>
376
+ </div>
377
+ </li>
378
+ ))}
379
+ </ul>
380
+ </div>
381
+
382
+ {/* Continue Learning */}
383
+ <div className="bg-gradient-to-br from-blue-500 to-purple-600 rounded-2xl shadow-xl p-6 text-white">
384
+ <h3 className="text-xl font-bold mb-4 flex items-center">
385
+ <svg className="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
386
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
387
+ </svg>
388
+ Continue Learning
389
+ </h3>
390
+ <div className="bg-white/20 backdrop-blur-sm rounded-xl p-4 mb-4">
391
+ <p className="font-semibold">Control Flow Module</p>
392
+ <p className="text-sm opacity-90 mt-1">75% complete • 65% mastery</p>
393
+ <div className="w-full bg-white/30 rounded-full h-2 mt-3">
394
+ <div className="bg-white h-2 rounded-full" style={{ width: '75%' }}></div>
395
+ </div>
396
+ </div>
397
+ <Link
398
+ href="/student/learn?module=mod2"
399
+ className="w-full bg-white text-blue-600 hover:bg-gray-100 font-semibold py-3 px-4 rounded-lg transition-all duration-300 transform hover:scale-105 block text-center"
400
+ prefetch={false}
401
+ >
402
+ Continue Learning
403
+ </Link>
404
+ </div>
405
+
406
+ {/* Quick Actions */}
407
+ <div className="bg-white/70 backdrop-blur-sm rounded-2xl shadow-xl border border-white/20 p-6">
408
+ <h3 className="text-xl font-bold text-gray-800 mb-4 flex items-center">
409
+ <svg className="w-5 h-5 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
410
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
411
+ </svg>
412
+ Quick Actions
413
+ </h3>
414
+ <div className="space-y-3">
415
+ <Link
416
+ href="/student/quiz"
417
+ className="flex items-center p-4 bg-gradient-to-r from-gray-50 to-gray-100 hover:from-blue-50 hover:to-purple-50 rounded-xl transition-all duration-300 transform hover:scale-[1.02] border border-gray-100 hover:border-blue-200"
418
+ prefetch={false}
419
+ >
420
+ <div className="w-10 h-10 bg-gradient-to-r from-blue-100 to-blue-200 rounded-lg flex items-center justify-center mr-3">
421
+ <svg className="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
422
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
423
+ </svg>
424
+ </div>
425
+ <span className="font-medium text-gray-800">Take a Quiz</span>
426
+ </Link>
427
+
428
+ <Link
429
+ href="/student/progress"
430
+ className="flex items-center p-4 bg-gradient-to-r from-gray-50 to-gray-100 hover:from-green-50 hover:to-teal-50 rounded-xl transition-all duration-300 transform hover:scale-[1.02] border border-gray-100 hover:border-green-200"
431
+ prefetch={false}
432
+ >
433
+ <div className="w-10 h-10 bg-gradient-to-r from-green-100 to-green-200 rounded-lg flex items-center justify-center mr-3">
434
+ <svg className="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
435
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
436
+ </svg>
437
+ </div>
438
+ <span className="font-medium text-gray-800">View Progress</span>
439
+ </Link>
440
+
441
+ <Link
442
+ href="/student/chat"
443
+ className="flex items-center p-4 bg-gradient-to-r from-gray-50 to-gray-100 hover:from-purple-50 hover:to-pink-50 rounded-xl transition-all duration-300 transform hover:scale-[1.02] border border-gray-100 hover:border-purple-200"
444
+ prefetch={false}
445
+ >
446
+ <div className="w-10 h-10 bg-gradient-to-r from-purple-100 to-purple-200 rounded-lg flex items-center justify-center mr-3">
447
+ <svg className="w-5 h-5 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
448
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
449
+ </svg>
450
+ </div>
451
+ <span className="font-medium text-gray-800">Chat with Tutor</span>
452
+ </Link>
453
+ </div>
454
+ </div>
455
+ </div>
456
+ </div>
457
+ </main>
458
+ </div>
459
+
460
+ <style jsx global>{`
461
+ .animation-delay-2000 {
462
+ animation-delay: 2s;
463
+ }
464
+ .animation-delay-4000 {
465
+ animation-delay: 4s;
466
+ }
467
+ @keyframes pulse {
468
+ 0%, 100% { opacity: 0.3; }
469
+ 50% { opacity: 0.4; }
470
+ }
471
+ .animate-pulse {
472
+ animation: pulse 6s cubic-bezier(0.4, 0, 0.6, 1) infinite;
473
+ }
474
+ `}</style>
475
+ </div>
476
+ );
477
+ }
app/student/learn/page.tsx ADDED
@@ -0,0 +1,521 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useRef, useEffect } from 'react';
4
+ import { useRouter } from 'next/navigation';
5
+ import dynamic from 'next/dynamic';
6
+
7
+ const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
8
+
9
+ // Dynamically import Monaco Editor with error handling to avoid SSR issues
10
+ const MonacoEditor = dynamic(
11
+ () => import('@monaco-editor/react'),
12
+ {
13
+ ssr: false,
14
+ loading: () => (
15
+ <div className="h-full w-full flex items-center justify-center bg-gray-900">
16
+ <div className="text-green-400 font-mono text-sm">Loading code editor...</div>
17
+ </div>
18
+ )
19
+ }
20
+ );
21
+
22
+ export default function LearnPage() {
23
+ const [code, setCode] = useState<string>('print("Hello, Python learner!")\n# Write your code here');
24
+ const [output, setOutput] = useState<string>('');
25
+ const [isLoading, setIsLoading] = useState<boolean>(false);
26
+ const [messages, setMessages] = useState<Array<{role: string, content: string}>>([
27
+ { role: 'assistant', content: 'Hello! I\'m your Python tutor. What would you like to learn today?' }
28
+ ]);
29
+ const [inputMessage, setInputMessage] = useState<string>('');
30
+ const editorRef = useRef<any>(null);
31
+
32
+ const handleRunCode = async () => {
33
+ setIsLoading(true);
34
+ setOutput('Running code...');
35
+
36
+ try {
37
+ const token = localStorage.getItem('learnflow_token');
38
+ const response = await fetch(`${API_URL}/execute`, {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ ...(token && { 'Authorization': `Bearer ${token}` }),
43
+ },
44
+ body: JSON.stringify({ code }),
45
+ });
46
+
47
+ if (response.ok) {
48
+ const data = await response.json();
49
+ if (data.error) {
50
+ setOutput(`Error:\n${data.error}\n\nOutput:\n${data.output || '(none)'}`);
51
+ } else {
52
+ setOutput(data.output || 'Code executed successfully (no output)');
53
+ }
54
+ } else {
55
+ // Fallback: simulate execution for demo
56
+ simulateExecution();
57
+ }
58
+ } catch (error) {
59
+ // API not available, simulate execution
60
+ console.log('Using simulated execution (API not available)');
61
+ simulateExecution();
62
+ }
63
+
64
+ setIsLoading(false);
65
+ };
66
+
67
+ const simulateExecution = () => {
68
+ // Simple Python simulation for common operations
69
+ const lines = code.split('\n');
70
+ let output = '';
71
+
72
+ for (const line of lines) {
73
+ const trimmed = line.trim();
74
+ if (trimmed.startsWith('print(')) {
75
+ const match = trimmed.match(/print\((.*)\)/);
76
+ if (match) {
77
+ let content = match[1];
78
+ // Handle string literals
79
+ if ((content.startsWith('"') && content.endsWith('"')) ||
80
+ (content.startsWith("'") && content.endsWith("'"))) {
81
+ output += content.slice(1, -1) + '\n';
82
+ } else if (content.startsWith('f"') || content.startsWith("f'")) {
83
+ output += content.slice(2, -1) + '\n';
84
+ } else {
85
+ output += content + '\n';
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ setOutput(output || 'Code executed successfully!\n(Simulated - connect API Gateway for real execution)');
92
+ };
93
+
94
+ const [isSending, setIsSending] = useState<boolean>(false);
95
+
96
+ const generateLocalResponse = (question: string): string => {
97
+ const lowerQuestion = question.toLowerCase();
98
+
99
+ if (lowerQuestion.includes('loop') || lowerQuestion.includes('for')) {
100
+ return `**For Loops in Python**
101
+
102
+ A for loop iterates over a sequence (list, string, range, etc.):
103
+
104
+ \`\`\`python
105
+ # Basic for loop
106
+ for i in range(5):
107
+ print(i) # Prints 0, 1, 2, 3, 4
108
+
109
+ # Loop through a list
110
+ fruits = ['apple', 'banana', 'cherry']
111
+ for fruit in fruits:
112
+ print(fruit)
113
+
114
+ # Loop with enumerate (get index too)
115
+ for index, fruit in enumerate(fruits):
116
+ print(f"{index}: {fruit}")
117
+ \`\`\`
118
+
119
+ **Key points:**
120
+ - \`range(n)\` generates numbers 0 to n-1
121
+ - Use \`break\` to exit early
122
+ - Use \`continue\` to skip to next iteration
123
+
124
+ Would you like me to explain more or try it in the code editor?`;
125
+ }
126
+
127
+ if (lowerQuestion.includes('function') || lowerQuestion.includes('def')) {
128
+ return `**Functions in Python**
129
+
130
+ Functions are reusable blocks of code:
131
+
132
+ \`\`\`python
133
+ # Basic function
134
+ def greet(name):
135
+ return f"Hello, {name}!"
136
+
137
+ # With default parameter
138
+ def greet(name, greeting="Hello"):
139
+ return f"{greeting}, {name}!"
140
+
141
+ # Multiple return values
142
+ def get_stats(numbers):
143
+ return min(numbers), max(numbers)
144
+
145
+ # Calling functions
146
+ message = greet("Alice")
147
+ minimum, maximum = get_stats([1, 2, 3, 4, 5])
148
+ \`\`\`
149
+
150
+ Try writing a function in the code editor!`;
151
+ }
152
+
153
+ if (lowerQuestion.includes('list')) {
154
+ return `**Lists in Python**
155
+
156
+ Lists are ordered, mutable collections:
157
+
158
+ \`\`\`python
159
+ # Create a list
160
+ numbers = [1, 2, 3, 4, 5]
161
+ mixed = [1, "hello", 3.14, True]
162
+
163
+ # Access elements
164
+ first = numbers[0] # 1
165
+ last = numbers[-1] # 5
166
+
167
+ # Modify lists
168
+ numbers.append(6) # Add to end
169
+ numbers.insert(0, 0) # Insert at index
170
+ numbers.remove(3) # Remove value
171
+
172
+ # List comprehension
173
+ squares = [x**2 for x in range(5)]
174
+ # Result: [0, 1, 4, 9, 16]
175
+ \`\`\`
176
+
177
+ Try creating a list in the code editor!`;
178
+ }
179
+
180
+ if (lowerQuestion.includes('if') || lowerQuestion.includes('condition')) {
181
+ return `**If Statements in Python**
182
+
183
+ Control flow with conditions:
184
+
185
+ \`\`\`python
186
+ age = 18
187
+
188
+ if age < 13:
189
+ print("Child")
190
+ elif age < 20:
191
+ print("Teenager")
192
+ else:
193
+ print("Adult")
194
+
195
+ # One-line conditional
196
+ status = "Adult" if age >= 18 else "Minor"
197
+
198
+ # Multiple conditions
199
+ if age >= 18 and has_license:
200
+ print("Can drive")
201
+ \`\`\`
202
+
203
+ Try writing an if statement in the code editor!`;
204
+ }
205
+
206
+ return `Great question about "${question}"!
207
+
208
+ I'm your Python AI tutor. I can help you with:
209
+ - **Python syntax** - variables, operators, data types
210
+ - **Control flow** - if/else, loops, functions
211
+ - **Data structures** - lists, dictionaries, tuples
212
+ - **Code debugging** - finding and fixing errors
213
+
214
+ Try asking about a specific topic, or write some code in the editor and I'll help you understand it!`;
215
+ };
216
+
217
+ const handleSendMessage = async () => {
218
+ if (!inputMessage.trim() || isSending) return;
219
+
220
+ const userMessage = { role: 'user', content: inputMessage };
221
+ const newMessages = [...messages, userMessage];
222
+ setMessages(newMessages);
223
+ const currentInput = inputMessage;
224
+ setInputMessage('');
225
+ setIsSending(true);
226
+
227
+ try {
228
+ const token = localStorage.getItem('learnflow_token');
229
+ const response = await fetch(`${API_URL}/chat`, {
230
+ method: 'POST',
231
+ headers: {
232
+ 'Content-Type': 'application/json',
233
+ ...(token && { 'Authorization': `Bearer ${token}` }),
234
+ },
235
+ body: JSON.stringify({
236
+ messages: newMessages.map(m => ({
237
+ role: m.role,
238
+ content: m.content
239
+ })),
240
+ user_id: 'learn-page-user',
241
+ }),
242
+ });
243
+
244
+ if (response.ok) {
245
+ const data = await response.json();
246
+ setMessages(prev => [...prev, {
247
+ role: 'assistant',
248
+ content: data.response
249
+ }]);
250
+ } else {
251
+ // Fallback to local response
252
+ setMessages(prev => [...prev, {
253
+ role: 'assistant',
254
+ content: generateLocalResponse(currentInput)
255
+ }]);
256
+ }
257
+ } catch (error) {
258
+ // API not available, use local response
259
+ console.log('Using local response (API not available)');
260
+ setMessages(prev => [...prev, {
261
+ role: 'assistant',
262
+ content: generateLocalResponse(currentInput)
263
+ }]);
264
+ }
265
+
266
+ setIsSending(false);
267
+ };
268
+
269
+ const handleEditorDidMount = (editor: any) => {
270
+ editorRef.current = editor;
271
+ };
272
+
273
+ return (
274
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
275
+ {/* Animated background elements */}
276
+ <div className="absolute inset-0 overflow-hidden">
277
+ <div className="absolute -top-40 -right-40 w-80 h-80 bg-purple-200 rounded-full mix-blend-multiply filter blur-xl opacity-20 animate-pulse"></div>
278
+ <div className="absolute -bottom-40 -left-40 w-80 h-80 bg-blue-200 rounded-full mix-blend-multiply filter blur-xl opacity-20 animate-pulse animation-delay-2000"></div>
279
+ </div>
280
+
281
+ <div className="relative">
282
+ <header className="bg-white/80 backdrop-blur-md shadow-lg border-b border-white/20 sticky top-0 z-10">
283
+ <div className="max-w-7xl mx-auto px-4 py-4 sm:px-6 lg:px-8">
284
+ <div className="flex items-center justify-between">
285
+ <div>
286
+ <h1 className="text-3xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
287
+ Python Learning Studio
288
+ </h1>
289
+ <p className="text-gray-600 mt-1">Interactive coding with AI-powered tutoring</p>
290
+ </div>
291
+ <div className="flex items-center space-x-4">
292
+ <div className="bg-gradient-to-r from-blue-100 to-purple-100 rounded-lg px-4 py-2">
293
+ <span className="text-sm font-medium text-gray-700">Module: Control Flow</span>
294
+ </div>
295
+ <div className="w-10 h-10 bg-gradient-to-r from-green-400 to-blue-500 rounded-full flex items-center justify-center">
296
+ <span className="text-white font-bold text-sm">A</span>
297
+ </div>
298
+ </div>
299
+ </div>
300
+ </div>
301
+ </header>
302
+
303
+ <main className="max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8">
304
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
305
+ {/* Chat Interface */}
306
+ <div className="bg-white/70 backdrop-blur-sm rounded-2xl shadow-xl border border-white/20 overflow-hidden">
307
+ <div className="p-6 border-b border-white/20">
308
+ <div className="flex items-center">
309
+ <div className="w-3 h-3 bg-green-500 rounded-full mr-2"></div>
310
+ <h2 className="text-xl font-bold text-gray-800 flex items-center">
311
+ <svg className="w-5 h-5 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
312
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
313
+ </svg>
314
+ AI Tutor Chat
315
+ </h2>
316
+ </div>
317
+ </div>
318
+
319
+ <div className="h-96 overflow-y-auto p-6 bg-gradient-to-b from-gray-50 to-gray-100">
320
+ {messages.map((msg, index) => (
321
+ <div
322
+ key={index}
323
+ className={`mb-4 p-4 rounded-2xl max-w-[85%] ${
324
+ msg.role === 'user'
325
+ ? 'ml-auto bg-gradient-to-r from-blue-500 to-purple-600 text-white shadow-lg'
326
+ : 'mr-auto bg-gradient-to-r from-green-100 to-blue-100 text-gray-800 shadow-md'
327
+ }`}
328
+ >
329
+ <div className="flex items-start">
330
+ {msg.role === 'assistant' && (
331
+ <div className="w-6 h-6 bg-gradient-to-r from-green-400 to-blue-500 rounded-full flex items-center justify-center mr-2 flex-shrink-0">
332
+ <svg className="w-3 h-3 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
333
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
334
+ </svg>
335
+ </div>
336
+ )}
337
+ <div className={`${msg.role === 'user' ? 'text-white' : 'text-gray-800'}`}>
338
+ {msg.content}
339
+ </div>
340
+ </div>
341
+ </div>
342
+ ))}
343
+ </div>
344
+
345
+ <div className="p-4 border-t border-white/20 bg-white/50">
346
+ <div className="flex">
347
+ <input
348
+ type="text"
349
+ value={inputMessage}
350
+ onChange={(e) => setInputMessage(e.target.value)}
351
+ onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
352
+ placeholder="Ask a Python question..."
353
+ className="flex-1 bg-white/80 backdrop-blur-sm border border-gray-200 rounded-l-xl px-4 py-3 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200"
354
+ />
355
+ <button
356
+ onClick={handleSendMessage}
357
+ disabled={isSending || !inputMessage.trim()}
358
+ className="bg-gradient-to-r from-blue-500 to-purple-600 hover:from-blue-600 hover:to-purple-700 text-white px-6 py-3 rounded-r-xl disabled:opacity-50 disabled:cursor-not-allowed transition-all duration-300 transform hover:scale-105 font-medium"
359
+ >
360
+ <div className="flex items-center">
361
+ {isSending ? (
362
+ <>
363
+ <svg className="animate-spin w-4 h-4 mr-1" fill="none" viewBox="0 0 24 24">
364
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
365
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
366
+ </svg>
367
+ Thinking...
368
+ </>
369
+ ) : (
370
+ <>
371
+ <svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
372
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
373
+ </svg>
374
+ Send
375
+ </>
376
+ )}
377
+ </div>
378
+ </button>
379
+ </div>
380
+ </div>
381
+ </div>
382
+
383
+ {/* Code Editor */}
384
+ <div className="bg-white/70 backdrop-blur-sm rounded-2xl shadow-xl border border-white/20 overflow-hidden">
385
+ <div className="p-5 border-b border-white/20 bg-gradient-to-r from-gray-50 to-gray-100">
386
+ <div className="flex justify-between items-center">
387
+ <h2 className="text-xl font-bold text-gray-800 flex items-center">
388
+ <svg className="w-5 h-5 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
389
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
390
+ </svg>
391
+ Python Code Editor
392
+ </h2>
393
+ <button
394
+ onClick={handleRunCode}
395
+ disabled={isLoading}
396
+ className="bg-gradient-to-r from-green-500 to-emerald-600 hover:from-green-600 hover:to-emerald-700 text-white px-6 py-2 rounded-lg disabled:opacity-50 transition-all duration-300 transform hover:scale-105 font-medium flex items-center"
397
+ >
398
+ {isLoading ? (
399
+ <>
400
+ <svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" fill="none" viewBox="0 0 24 24">
401
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
402
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
403
+ </svg>
404
+ Running...
405
+ </>
406
+ ) : (
407
+ <>
408
+ <svg className="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
409
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.828 14.828a4 4 0 01-5.656 0M9 10h1m4 0h1m-6 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
410
+ </svg>
411
+ Run Code
412
+ </>
413
+ )}
414
+ </button>
415
+ </div>
416
+ </div>
417
+
418
+ <div className="h-80">
419
+ <MonacoEditor
420
+ height="100%"
421
+ language="python"
422
+ value={code}
423
+ onChange={(value) => setCode(value || '')}
424
+ onMount={handleEditorDidMount}
425
+ theme="vs-light"
426
+ options={{
427
+ minimap: { enabled: true },
428
+ fontSize: 14,
429
+ scrollBeyondLastLine: false,
430
+ automaticLayout: true,
431
+ fontFamily: 'Consolas, "Courier New", monospace',
432
+ }}
433
+ />
434
+ </div>
435
+
436
+ <div className="p-4 border-t border-white/20 bg-gray-50/50">
437
+ <h3 className="font-bold text-gray-800 mb-2 flex items-center">
438
+ <svg className="w-4 h-4 mr-2 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
439
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
440
+ </svg>
441
+ Output
442
+ </h3>
443
+ <div className="bg-gray-900 text-green-400 p-4 rounded-lg font-mono text-sm h-32 overflow-auto border border-gray-700">
444
+ {output || 'Click "Run Code" to execute your Python code...'}
445
+ </div>
446
+ </div>
447
+ </div>
448
+ </div>
449
+
450
+ {/* Learning Resources */}
451
+ <div className="bg-white/70 backdrop-blur-sm rounded-2xl shadow-xl border border-white/20 p-6">
452
+ <h2 className="text-2xl font-bold text-gray-800 mb-6 flex items-center">
453
+ <svg className="w-6 h-6 mr-2 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
454
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.746 0 3.332.477 4.5 1.253v13C19.832 18.477 18.246 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
455
+ </svg>
456
+ Learning Resources
457
+ </h2>
458
+
459
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
460
+ <div className="bg-gradient-to-br from-blue-50 to-blue-100 rounded-xl p-6 border border-white/50 hover:shadow-lg transition-all duration-300 transform hover:-translate-y-1">
461
+ <div className="w-12 h-12 bg-gradient-to-r from-blue-500 to-blue-600 rounded-lg flex items-center justify-center mb-4">
462
+ <svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
463
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
464
+ </svg>
465
+ </div>
466
+ <h3 className="font-bold text-lg text-gray-800 mb-2">Python Basics</h3>
467
+ <p className="text-gray-600 mb-4">Variables, data types, operators, and basic syntax</p>
468
+ <button className="bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white px-4 py-2 rounded-lg transition-all duration-300 transform hover:scale-105">
469
+ Start Module
470
+ </button>
471
+ </div>
472
+
473
+ <div className="bg-gradient-to-br from-purple-50 to-purple-100 rounded-xl p-6 border border-white/50 hover:shadow-lg transition-all duration-300 transform hover:-translate-y-1">
474
+ <div className="w-12 h-12 bg-gradient-to-r from-purple-500 to-purple-600 rounded-lg flex items-center justify-center mb-4">
475
+ <svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
476
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
477
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
478
+ </svg>
479
+ </div>
480
+ <h3 className="font-bold text-lg text-gray-800 mb-2">Control Flow</h3>
481
+ <p className="text-gray-600 mb-4">If statements, loops, functions, and control structures</p>
482
+ <button className="bg-gradient-to-r from-purple-500 to-purple-600 hover:from-purple-600 hover:to-purple-700 text-white px-4 py-2 rounded-lg transition-all duration-300 transform hover:scale-105">
483
+ Start Module
484
+ </button>
485
+ </div>
486
+
487
+ <div className="bg-gradient-to-br from-green-50 to-green-100 rounded-xl p-6 border border-white/50 hover:shadow-lg transition-all duration-300 transform hover:-translate-y-1">
488
+ <div className="w-12 h-12 bg-gradient-to-r from-green-500 to-green-600 rounded-lg flex items-center justify-center mb-4">
489
+ <svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
490
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" />
491
+ </svg>
492
+ </div>
493
+ <h3 className="font-bold text-lg text-gray-800 mb-2">Practice Exercises</h3>
494
+ <p className="text-gray-600 mb-4">Hands-on coding challenges and projects</p>
495
+ <button className="bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 text-white px-4 py-2 rounded-lg transition-all duration-300 transform hover:scale-105">
496
+ Start Practice
497
+ </button>
498
+ </div>
499
+ </div>
500
+ </div>
501
+ </main>
502
+ </div>
503
+
504
+ <style jsx global>{`
505
+ .animation-delay-2000 {
506
+ animation-delay: 2s;
507
+ }
508
+ .animation-delay-4000 {
509
+ animation-delay: 4s;
510
+ }
511
+ @keyframes pulse {
512
+ 0%, 100% { opacity: 0.2; }
513
+ 50% { opacity: 0.3; }
514
+ }
515
+ .animate-pulse {
516
+ animation: pulse 6s cubic-bezier(0.4, 0, 0.6, 1) infinite;
517
+ }
518
+ `}</style>
519
+ </div>
520
+ );
521
+ }
app/student/progress/page.tsx ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import { useRouter } from 'next/navigation';
5
+ import Link from 'next/link';
6
+
7
+ type User = {
8
+ id: string;
9
+ name: string;
10
+ email: string;
11
+ role: string;
12
+ };
13
+
14
+ type ModuleProgress = {
15
+ id: string;
16
+ name: string;
17
+ mastery: number;
18
+ completed: number;
19
+ total: number;
20
+ lastActivity: string;
21
+ };
22
+
23
+ export default function ProgressPage() {
24
+ const router = useRouter();
25
+ const [user, setUser] = useState<User | null>(null);
26
+ const [isLoading, setIsLoading] = useState(true);
27
+
28
+ const overallStats = {
29
+ totalMastery: 72,
30
+ totalHours: 24,
31
+ streak: 5,
32
+ quizzesTaken: 12,
33
+ exercisesCompleted: 45,
34
+ rank: 'Intermediate'
35
+ };
36
+
37
+ const moduleProgress: ModuleProgress[] = [
38
+ { id: 'mod1', name: 'Python Basics', mastery: 92, completed: 10, total: 10, lastActivity: '2 days ago' },
39
+ { id: 'mod2', name: 'Control Flow', mastery: 75, completed: 8, total: 12, lastActivity: '1 day ago' },
40
+ { id: 'mod3', name: 'Functions', mastery: 45, completed: 5, total: 15, lastActivity: 'Today' },
41
+ { id: 'mod4', name: 'Data Structures', mastery: 30, completed: 3, total: 18, lastActivity: '3 days ago' },
42
+ { id: 'mod5', name: 'OOP', mastery: 0, completed: 0, total: 20, lastActivity: 'Not started' },
43
+ { id: 'mod6', name: 'File Operations', mastery: 0, completed: 0, total: 10, lastActivity: 'Not started' },
44
+ ];
45
+
46
+ const recentAchievements = [
47
+ { id: 1, title: 'Quiz Master', description: 'Scored 100% on 3 quizzes', icon: '🏆', date: '2 days ago' },
48
+ { id: 2, title: 'Code Warrior', description: 'Completed 10 exercises in a day', icon: '⚔️', date: '5 days ago' },
49
+ { id: 3, title: 'Fast Learner', description: 'Finished a module in record time', icon: '🚀', date: '1 week ago' },
50
+ ];
51
+
52
+ const weeklyActivity = [
53
+ { day: 'Mon', hours: 2 },
54
+ { day: 'Tue', hours: 1.5 },
55
+ { day: 'Wed', hours: 3 },
56
+ { day: 'Thu', hours: 2.5 },
57
+ { day: 'Fri', hours: 1 },
58
+ { day: 'Sat', hours: 4 },
59
+ { day: 'Sun', hours: 2 },
60
+ ];
61
+
62
+ useEffect(() => {
63
+ const currentUser = localStorage.getItem('learnflow_current_user');
64
+ if (!currentUser) {
65
+ router.push('/');
66
+ return;
67
+ }
68
+
69
+ const parsedUser = JSON.parse(currentUser);
70
+ if (parsedUser.role !== 'student') {
71
+ router.push('/teacher/dashboard');
72
+ return;
73
+ }
74
+
75
+ setUser(parsedUser);
76
+ setIsLoading(false);
77
+ }, [router]);
78
+
79
+ if (isLoading) {
80
+ return (
81
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex items-center justify-center">
82
+ <div className="text-center">
83
+ <div className="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
84
+ <p className="text-gray-600">Loading progress...</p>
85
+ </div>
86
+ </div>
87
+ );
88
+ }
89
+
90
+ return (
91
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
92
+ <header className="bg-white/80 backdrop-blur-md shadow-lg border-b border-white/20 sticky top-0 z-10">
93
+ <div className="max-w-7xl mx-auto px-4 py-4 sm:px-6 lg:px-8">
94
+ <div className="flex items-center justify-between">
95
+ <Link href="/student/dashboard" className="flex items-center space-x-3">
96
+ <div className="w-10 h-10 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
97
+ <span className="text-white font-bold text-sm">LF</span>
98
+ </div>
99
+ <span className="text-xl font-bold text-gray-900">My Progress</span>
100
+ </Link>
101
+ <Link
102
+ href="/student/dashboard"
103
+ className="text-gray-600 hover:text-gray-800 font-medium flex items-center"
104
+ >
105
+ <svg className="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
106
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
107
+ </svg>
108
+ Back to Dashboard
109
+ </Link>
110
+ </div>
111
+ </div>
112
+ </header>
113
+
114
+ <main className="max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8">
115
+ {/* Overall Stats */}
116
+ <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4 mb-8">
117
+ <div className="bg-white rounded-xl p-4 shadow-lg">
118
+ <div className="text-3xl font-bold text-blue-600">{overallStats.totalMastery}%</div>
119
+ <div className="text-sm text-gray-500">Overall Mastery</div>
120
+ </div>
121
+ <div className="bg-white rounded-xl p-4 shadow-lg">
122
+ <div className="text-3xl font-bold text-green-600">{overallStats.totalHours}h</div>
123
+ <div className="text-sm text-gray-500">Total Hours</div>
124
+ </div>
125
+ <div className="bg-white rounded-xl p-4 shadow-lg">
126
+ <div className="text-3xl font-bold text-orange-600">{overallStats.streak}</div>
127
+ <div className="text-sm text-gray-500">Day Streak</div>
128
+ </div>
129
+ <div className="bg-white rounded-xl p-4 shadow-lg">
130
+ <div className="text-3xl font-bold text-purple-600">{overallStats.quizzesTaken}</div>
131
+ <div className="text-sm text-gray-500">Quizzes Taken</div>
132
+ </div>
133
+ <div className="bg-white rounded-xl p-4 shadow-lg">
134
+ <div className="text-3xl font-bold text-teal-600">{overallStats.exercisesCompleted}</div>
135
+ <div className="text-sm text-gray-500">Exercises Done</div>
136
+ </div>
137
+ <div className="bg-white rounded-xl p-4 shadow-lg">
138
+ <div className="text-3xl font-bold text-indigo-600">{overallStats.rank}</div>
139
+ <div className="text-sm text-gray-500">Current Rank</div>
140
+ </div>
141
+ </div>
142
+
143
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
144
+ {/* Module Progress */}
145
+ <div className="lg:col-span-2 bg-white rounded-2xl shadow-xl p-6">
146
+ <h2 className="text-xl font-bold text-gray-900 mb-6">Module Progress</h2>
147
+ <div className="space-y-4">
148
+ {moduleProgress.map((module) => (
149
+ <div key={module.id} className="border border-gray-100 rounded-xl p-4">
150
+ <div className="flex justify-between items-start mb-2">
151
+ <div>
152
+ <h3 className="font-semibold text-gray-900">{module.name}</h3>
153
+ <p className="text-sm text-gray-500">{module.completed}/{module.total} lessons completed</p>
154
+ </div>
155
+ <span className={`px-3 py-1 rounded-full text-sm font-medium ${
156
+ module.mastery >= 80 ? 'bg-green-100 text-green-800' :
157
+ module.mastery >= 50 ? 'bg-yellow-100 text-yellow-800' :
158
+ module.mastery > 0 ? 'bg-orange-100 text-orange-800' :
159
+ 'bg-gray-100 text-gray-600'
160
+ }`}>
161
+ {module.mastery}% Mastery
162
+ </span>
163
+ </div>
164
+ <div className="w-full bg-gray-200 rounded-full h-2 mb-2">
165
+ <div
166
+ className={`h-2 rounded-full ${
167
+ module.mastery >= 80 ? 'bg-green-500' :
168
+ module.mastery >= 50 ? 'bg-yellow-500' :
169
+ module.mastery > 0 ? 'bg-orange-500' :
170
+ 'bg-gray-400'
171
+ }`}
172
+ style={{ width: `${module.mastery}%` }}
173
+ ></div>
174
+ </div>
175
+ <p className="text-xs text-gray-400">Last activity: {module.lastActivity}</p>
176
+ </div>
177
+ ))}
178
+ </div>
179
+ </div>
180
+
181
+ {/* Sidebar */}
182
+ <div className="space-y-6">
183
+ {/* Weekly Activity */}
184
+ <div className="bg-white rounded-2xl shadow-xl p-6">
185
+ <h2 className="text-xl font-bold text-gray-900 mb-4">Weekly Activity</h2>
186
+ <div className="flex items-end justify-between h-32">
187
+ {weeklyActivity.map((day, index) => (
188
+ <div key={index} className="flex flex-col items-center">
189
+ <div
190
+ className="w-8 bg-blue-500 rounded-t"
191
+ style={{ height: `${(day.hours / 4) * 100}%` }}
192
+ ></div>
193
+ <span className="text-xs text-gray-500 mt-2">{day.day}</span>
194
+ </div>
195
+ ))}
196
+ </div>
197
+ <div className="text-center mt-4 text-sm text-gray-600">
198
+ Total this week: {weeklyActivity.reduce((acc, d) => acc + d.hours, 0)} hours
199
+ </div>
200
+ </div>
201
+
202
+ {/* Achievements */}
203
+ <div className="bg-white rounded-2xl shadow-xl p-6">
204
+ <h2 className="text-xl font-bold text-gray-900 mb-4">Recent Achievements</h2>
205
+ <div className="space-y-4">
206
+ {recentAchievements.map((achievement) => (
207
+ <div key={achievement.id} className="flex items-start space-x-3">
208
+ <div className="text-2xl">{achievement.icon}</div>
209
+ <div>
210
+ <h3 className="font-semibold text-gray-900">{achievement.title}</h3>
211
+ <p className="text-sm text-gray-500">{achievement.description}</p>
212
+ <p className="text-xs text-gray-400">{achievement.date}</p>
213
+ </div>
214
+ </div>
215
+ ))}
216
+ </div>
217
+ </div>
218
+ </div>
219
+ </div>
220
+ </main>
221
+ </div>
222
+ );
223
+ }
app/student/quiz/page.tsx ADDED
@@ -0,0 +1,310 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import { useRouter } from 'next/navigation';
5
+ import Link from 'next/link';
6
+
7
+ type Question = {
8
+ id: number;
9
+ question: string;
10
+ options: string[];
11
+ correctAnswer: number;
12
+ explanation: string;
13
+ };
14
+
15
+ type User = {
16
+ id: string;
17
+ name: string;
18
+ email: string;
19
+ role: string;
20
+ };
21
+
22
+ export default function QuizPage() {
23
+ const router = useRouter();
24
+ const [user, setUser] = useState<User | null>(null);
25
+ const [isLoading, setIsLoading] = useState(true);
26
+ const [currentQuestion, setCurrentQuestion] = useState(0);
27
+ const [selectedAnswer, setSelectedAnswer] = useState<number | null>(null);
28
+ const [showResult, setShowResult] = useState(false);
29
+ const [score, setScore] = useState(0);
30
+ const [quizCompleted, setQuizCompleted] = useState(false);
31
+ const [answers, setAnswers] = useState<number[]>([]);
32
+
33
+ const questions: Question[] = [
34
+ {
35
+ id: 1,
36
+ question: "What is the correct way to create a variable in Python?",
37
+ options: ["var x = 5", "x = 5", "int x = 5", "let x = 5"],
38
+ correctAnswer: 1,
39
+ explanation: "In Python, you create variables by simply assigning a value. No keyword like 'var', 'let', or type declaration is needed."
40
+ },
41
+ {
42
+ id: 2,
43
+ question: "Which of the following is a valid Python list?",
44
+ options: ["[1, 2, 3]", "{1, 2, 3}", "(1, 2, 3)", "<1, 2, 3>"],
45
+ correctAnswer: 0,
46
+ explanation: "Lists in Python are created using square brackets []. Curly braces {} create sets or dicts, and parentheses () create tuples."
47
+ },
48
+ {
49
+ id: 3,
50
+ question: "What does the 'len()' function do?",
51
+ options: ["Converts to lowercase", "Returns the length of an object", "Creates a new list", "Removes an item"],
52
+ correctAnswer: 1,
53
+ explanation: "The len() function returns the number of items in an object like a string, list, tuple, etc."
54
+ },
55
+ {
56
+ id: 4,
57
+ question: "How do you start a for loop in Python?",
58
+ options: ["for (i = 0; i < 10; i++)", "for i in range(10):", "foreach i in range(10)", "loop i from 0 to 10"],
59
+ correctAnswer: 1,
60
+ explanation: "Python uses 'for item in iterable:' syntax. The range() function generates a sequence of numbers."
61
+ },
62
+ {
63
+ id: 5,
64
+ question: "What will print(type(5.0)) output?",
65
+ options: ["<class 'int'>", "<class 'float'>", "<class 'number'>", "<class 'decimal'>"],
66
+ correctAnswer: 1,
67
+ explanation: "5.0 is a floating-point number in Python, so type() returns <class 'float'>."
68
+ }
69
+ ];
70
+
71
+ useEffect(() => {
72
+ const currentUser = localStorage.getItem('learnflow_current_user');
73
+ if (!currentUser) {
74
+ router.push('/');
75
+ return;
76
+ }
77
+
78
+ const parsedUser = JSON.parse(currentUser);
79
+ if (parsedUser.role !== 'student') {
80
+ router.push('/teacher/dashboard');
81
+ return;
82
+ }
83
+
84
+ setUser(parsedUser);
85
+ setIsLoading(false);
86
+ }, [router]);
87
+
88
+ const handleAnswerSelect = (answerIndex: number) => {
89
+ if (showResult) return;
90
+ setSelectedAnswer(answerIndex);
91
+ };
92
+
93
+ const handleSubmitAnswer = () => {
94
+ if (selectedAnswer === null) return;
95
+
96
+ const newAnswers = [...answers, selectedAnswer];
97
+ setAnswers(newAnswers);
98
+
99
+ if (selectedAnswer === questions[currentQuestion].correctAnswer) {
100
+ setScore(score + 1);
101
+ }
102
+
103
+ setShowResult(true);
104
+ };
105
+
106
+ const handleNextQuestion = () => {
107
+ if (currentQuestion < questions.length - 1) {
108
+ setCurrentQuestion(currentQuestion + 1);
109
+ setSelectedAnswer(null);
110
+ setShowResult(false);
111
+ } else {
112
+ setQuizCompleted(true);
113
+ }
114
+ };
115
+
116
+ const handleRestartQuiz = () => {
117
+ setCurrentQuestion(0);
118
+ setSelectedAnswer(null);
119
+ setShowResult(false);
120
+ setScore(0);
121
+ setQuizCompleted(false);
122
+ setAnswers([]);
123
+ };
124
+
125
+ if (isLoading) {
126
+ return (
127
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 flex items-center justify-center">
128
+ <div className="text-center">
129
+ <div className="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
130
+ <p className="text-gray-600">Loading quiz...</p>
131
+ </div>
132
+ </div>
133
+ );
134
+ }
135
+
136
+ if (quizCompleted) {
137
+ const percentage = Math.round((score / questions.length) * 100);
138
+ return (
139
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
140
+ <header className="bg-white/80 backdrop-blur-md shadow-lg border-b border-white/20 sticky top-0 z-10">
141
+ <div className="max-w-4xl mx-auto px-4 py-4 sm:px-6 lg:px-8">
142
+ <div className="flex items-center justify-between">
143
+ <Link href="/student/dashboard" className="flex items-center space-x-3">
144
+ <div className="w-10 h-10 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
145
+ <span className="text-white font-bold text-sm">LF</span>
146
+ </div>
147
+ <span className="text-xl font-bold text-gray-900">LearnFlow</span>
148
+ </Link>
149
+ </div>
150
+ </div>
151
+ </header>
152
+
153
+ <main className="max-w-2xl mx-auto px-4 py-12">
154
+ <div className="bg-white rounded-2xl shadow-xl p-8 text-center">
155
+ <div className={`w-24 h-24 mx-auto mb-6 rounded-full flex items-center justify-center ${
156
+ percentage >= 80 ? 'bg-green-100' : percentage >= 60 ? 'bg-yellow-100' : 'bg-red-100'
157
+ }`}>
158
+ <span className={`text-4xl font-bold ${
159
+ percentage >= 80 ? 'text-green-600' : percentage >= 60 ? 'text-yellow-600' : 'text-red-600'
160
+ }`}>{percentage}%</span>
161
+ </div>
162
+
163
+ <h2 className="text-2xl font-bold text-gray-900 mb-2">Quiz Completed!</h2>
164
+ <p className="text-gray-600 mb-6">
165
+ You scored {score} out of {questions.length} questions correctly.
166
+ </p>
167
+
168
+ <div className={`p-4 rounded-lg mb-8 ${
169
+ percentage >= 80 ? 'bg-green-50 text-green-800' :
170
+ percentage >= 60 ? 'bg-yellow-50 text-yellow-800' :
171
+ 'bg-red-50 text-red-800'
172
+ }`}>
173
+ {percentage >= 80 ? "Excellent! You've mastered this topic!" :
174
+ percentage >= 60 ? "Good job! Keep practicing to improve." :
175
+ "Keep learning! Review the material and try again."}
176
+ </div>
177
+
178
+ <div className="flex gap-4 justify-center">
179
+ <button
180
+ onClick={handleRestartQuiz}
181
+ className="bg-blue-500 hover:bg-blue-600 text-white px-6 py-3 rounded-lg font-medium transition-colors"
182
+ >
183
+ Retry Quiz
184
+ </button>
185
+ <Link
186
+ href="/student/dashboard"
187
+ className="bg-gray-200 hover:bg-gray-300 text-gray-800 px-6 py-3 rounded-lg font-medium transition-colors"
188
+ >
189
+ Back to Dashboard
190
+ </Link>
191
+ </div>
192
+ </div>
193
+ </main>
194
+ </div>
195
+ );
196
+ }
197
+
198
+ const question = questions[currentQuestion];
199
+
200
+ return (
201
+ <div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100">
202
+ <header className="bg-white/80 backdrop-blur-md shadow-lg border-b border-white/20 sticky top-0 z-10">
203
+ <div className="max-w-4xl mx-auto px-4 py-4 sm:px-6 lg:px-8">
204
+ <div className="flex items-center justify-between">
205
+ <Link href="/student/dashboard" className="flex items-center space-x-3">
206
+ <div className="w-10 h-10 bg-gradient-to-r from-blue-500 to-purple-600 rounded-lg flex items-center justify-center">
207
+ <span className="text-white font-bold text-sm">LF</span>
208
+ </div>
209
+ <span className="text-xl font-bold text-gray-900">LearnFlow Quiz</span>
210
+ </Link>
211
+ <div className="text-sm text-gray-600">
212
+ Question {currentQuestion + 1} of {questions.length}
213
+ </div>
214
+ </div>
215
+ </div>
216
+ </header>
217
+
218
+ <main className="max-w-2xl mx-auto px-4 py-8">
219
+ {/* Progress Bar */}
220
+ <div className="mb-8">
221
+ <div className="w-full bg-gray-200 rounded-full h-2">
222
+ <div
223
+ className="bg-blue-500 h-2 rounded-full transition-all duration-300"
224
+ style={{ width: `${((currentQuestion + 1) / questions.length) * 100}%` }}
225
+ ></div>
226
+ </div>
227
+ </div>
228
+
229
+ <div className="bg-white rounded-2xl shadow-xl p-8">
230
+ <h2 className="text-xl font-bold text-gray-900 mb-6">{question.question}</h2>
231
+
232
+ <div className="space-y-3 mb-8">
233
+ {question.options.map((option, index) => (
234
+ <button
235
+ key={index}
236
+ onClick={() => handleAnswerSelect(index)}
237
+ disabled={showResult}
238
+ className={`w-full p-4 text-left rounded-lg border-2 transition-all ${
239
+ showResult
240
+ ? index === question.correctAnswer
241
+ ? 'border-green-500 bg-green-50'
242
+ : index === selectedAnswer
243
+ ? 'border-red-500 bg-red-50'
244
+ : 'border-gray-200'
245
+ : selectedAnswer === index
246
+ ? 'border-blue-500 bg-blue-50'
247
+ : 'border-gray-200 hover:border-blue-300 hover:bg-blue-50'
248
+ }`}
249
+ >
250
+ <div className="flex items-center">
251
+ <span className={`w-8 h-8 rounded-full flex items-center justify-center mr-3 text-sm font-medium ${
252
+ showResult
253
+ ? index === question.correctAnswer
254
+ ? 'bg-green-500 text-white'
255
+ : index === selectedAnswer
256
+ ? 'bg-red-500 text-white'
257
+ : 'bg-gray-200 text-gray-600'
258
+ : selectedAnswer === index
259
+ ? 'bg-blue-500 text-white'
260
+ : 'bg-gray-200 text-gray-600'
261
+ }`}>
262
+ {String.fromCharCode(65 + index)}
263
+ </span>
264
+ <span className="text-gray-800">{option}</span>
265
+ </div>
266
+ </button>
267
+ ))}
268
+ </div>
269
+
270
+ {showResult && (
271
+ <div className={`p-4 rounded-lg mb-6 ${
272
+ selectedAnswer === question.correctAnswer ? 'bg-green-50 text-green-800' : 'bg-red-50 text-red-800'
273
+ }`}>
274
+ <p className="font-medium mb-1">
275
+ {selectedAnswer === question.correctAnswer ? 'Correct!' : 'Incorrect!'}
276
+ </p>
277
+ <p className="text-sm">{question.explanation}</p>
278
+ </div>
279
+ )}
280
+
281
+ <div className="flex justify-between">
282
+ <Link
283
+ href="/student/dashboard"
284
+ className="text-gray-600 hover:text-gray-800 font-medium"
285
+ >
286
+ Exit Quiz
287
+ </Link>
288
+
289
+ {!showResult ? (
290
+ <button
291
+ onClick={handleSubmitAnswer}
292
+ disabled={selectedAnswer === null}
293
+ className="bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 disabled:cursor-not-allowed text-white px-6 py-2 rounded-lg font-medium transition-colors"
294
+ >
295
+ Submit Answer
296
+ </button>
297
+ ) : (
298
+ <button
299
+ onClick={handleNextQuestion}
300
+ className="bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded-lg font-medium transition-colors"
301
+ >
302
+ {currentQuestion < questions.length - 1 ? 'Next Question' : 'See Results'}
303
+ </button>
304
+ )}
305
+ </div>
306
+ </div>
307
+ </main>
308
+ </div>
309
+ );
310
+ }
app/teacher/dashboard/page.tsx ADDED
@@ -0,0 +1,317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import { useState, useEffect } from 'react';
4
+ import { useRouter } from 'next/navigation';
5
+ import Link from 'next/link';
6
+
7
+ type Student = {
8
+ id: string;
9
+ name: string;
10
+ currentModule: string;
11
+ masteryPercentage: number;
12
+ lastActive: string;
13
+ status: 'active' | 'struggling' | 'idle';
14
+ };
15
+
16
+ type StruggleAlert = {
17
+ id: string;
18
+ studentId: string;
19
+ studentName: string;
20
+ issue: string;
21
+ timestamp: string;
22
+ resolved: boolean;
23
+ };
24
+
25
+ type User = {
26
+ id: string;
27
+ name: string;
28
+ email: string;
29
+ role: string;
30
+ };
31
+
32
+ export default function TeacherDashboard() {
33
+ const router = useRouter();
34
+ const [user, setUser] = useState<User | null>(null);
35
+ const [isLoading, setIsLoading] = useState(true);
36
+
37
+ const [students, setStudents] = useState<Student[]>([
38
+ { id: '1', name: 'Alex Johnson', currentModule: 'Control Flow', masteryPercentage: 65, lastActive: '2026-01-15 14:30', status: 'active' },
39
+ { id: '2', name: 'Sam Smith', currentModule: 'Functions', masteryPercentage: 42, lastActive: '2026-01-15 13:45', status: 'struggling' },
40
+ { id: '3', name: 'Taylor Brown', currentModule: 'Data Structures', masteryPercentage: 88, lastActive: '2026-01-15 15:15', status: 'active' },
41
+ { id: '4', name: 'Jordan Davis', currentModule: 'Basics', masteryPercentage: 92, lastActive: '2026-01-15 12:20', status: 'idle' },
42
+ { id: '5', name: 'Casey Wilson', currentModule: 'OOP', masteryPercentage: 35, lastActive: '2026-01-15 14:50', status: 'struggling' },
43
+ { id: '6', name: 'Morgan Lee', currentModule: 'Files', masteryPercentage: 76, lastActive: '2026-01-15 15:05', status: 'active' }
44
+ ]);
45
+
46
+ const [alerts, setAlerts] = useState<StruggleAlert[]>([
47
+ { id: 'a1', studentId: '2', studentName: 'Sam Smith', issue: 'Stuck on for loop exercise for 15 minutes', timestamp: '2026-01-15 14:25', resolved: false },
48
+ { id: 'a2', studentId: '5', studentName: 'Casey Wilson', issue: 'Repeated the same syntax error 3 times', timestamp: '2026-01-15 14:48', resolved: false }
49
+ ]);
50
+
51
+ const [classStats, setClassStats] = useState({
52
+ totalStudents: 24,
53
+ activeStudents: 18,
54
+ averageMastery: 68,
55
+ strugglingStudents: 4
56
+ });
57
+
58
+ useEffect(() => {
59
+ // Check if user is logged in
60
+ const currentUser = localStorage.getItem('learnflow_current_user');
61
+ if (!currentUser) {
62
+ router.push('/');
63
+ return;
64
+ }
65
+
66
+ const parsedUser = JSON.parse(currentUser);
67
+ if (parsedUser.role !== 'teacher') {
68
+ router.push('/student/dashboard');
69
+ return;
70
+ }
71
+
72
+ setUser(parsedUser);
73
+ setIsLoading(false);
74
+ }, [router]);
75
+
76
+ const handleLogout = () => {
77
+ localStorage.removeItem('learnflow_current_user');
78
+ router.push('/');
79
+ };
80
+
81
+ if (isLoading) {
82
+ return (
83
+ <div className="min-h-screen bg-gray-50 flex items-center justify-center">
84
+ <div className="text-center">
85
+ <div className="w-16 h-16 border-4 border-purple-500 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
86
+ <p className="text-gray-600">Loading dashboard...</p>
87
+ </div>
88
+ </div>
89
+ );
90
+ }
91
+
92
+ const resolveAlert = (alertId: string) => {
93
+ setAlerts(alerts.map(alert =>
94
+ alert.id === alertId ? {...alert, resolved: true} : alert
95
+ ));
96
+ };
97
+
98
+ return (
99
+ <div className="min-h-screen bg-gray-50">
100
+ <header className="bg-white shadow">
101
+ <div className="max-w-7xl mx-auto px-4 py-6 sm:px-6 lg:px-8">
102
+ <div className="flex justify-between items-center">
103
+ <div>
104
+ <div className="flex items-center space-x-4">
105
+ <Link href="/" className="flex items-center">
106
+ <div className="w-10 h-10 bg-gradient-to-r from-purple-500 to-indigo-600 rounded-lg flex items-center justify-center">
107
+ <span className="text-white font-bold text-sm">LF</span>
108
+ </div>
109
+ </Link>
110
+ <div>
111
+ <h1 className="text-2xl font-bold text-gray-900">Teacher Dashboard</h1>
112
+ <p className="text-sm text-gray-500">Welcome, {user?.name || 'Teacher'}</p>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ <div className="flex items-center space-x-4">
117
+ <div className="flex items-center space-x-3 bg-gray-100 rounded-full px-4 py-2">
118
+ <div className="w-8 h-8 bg-gradient-to-r from-purple-400 to-indigo-500 rounded-full flex items-center justify-center">
119
+ <span className="text-white text-sm font-semibold">{user?.name?.charAt(0).toUpperCase() || 'T'}</span>
120
+ </div>
121
+ <span className="text-gray-700 font-medium">{user?.name?.split(' ')[0] || 'Teacher'}</span>
122
+ </div>
123
+ <button
124
+ onClick={handleLogout}
125
+ className="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg transition-colors"
126
+ >
127
+ Logout
128
+ </button>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </header>
133
+
134
+ <main className="max-w-7xl mx-auto px-4 py-8 sm:px-6 lg:px-8">
135
+ {/* Class Statistics */}
136
+ <div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4 mb-8">
137
+ <div className="bg-white overflow-hidden shadow rounded-lg">
138
+ <div className="px-4 py-5 sm:p-6">
139
+ <div className="flex items-center">
140
+ <div className="flex-shrink-0 bg-blue-500 rounded-md p-3">
141
+ <svg className="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
142
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
143
+ </svg>
144
+ </div>
145
+ <div className="ml-5 w-0 flex-1">
146
+ <dl>
147
+ <dt className="text-sm font-medium text-gray-500 truncate">Total Students</dt>
148
+ <dd className="text-2xl font-semibold text-gray-900">{classStats.totalStudents}</dd>
149
+ </dl>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </div>
154
+
155
+ <div className="bg-white overflow-hidden shadow rounded-lg">
156
+ <div className="px-4 py-5 sm:p-6">
157
+ <div className="flex items-center">
158
+ <div className="flex-shrink-0 bg-green-500 rounded-md p-3">
159
+ <svg className="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
160
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
161
+ </svg>
162
+ </div>
163
+ <div className="ml-5 w-0 flex-1">
164
+ <dl>
165
+ <dt className="text-sm font-medium text-gray-500 truncate">Active Students</dt>
166
+ <dd className="text-2xl font-semibold text-gray-900">{classStats.activeStudents}</dd>
167
+ </dl>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ </div>
172
+
173
+ <div className="bg-white overflow-hidden shadow rounded-lg">
174
+ <div className="px-4 py-5 sm:p-6">
175
+ <div className="flex items-center">
176
+ <div className="flex-shrink-0 bg-yellow-500 rounded-md p-3">
177
+ <svg className="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
178
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
179
+ </svg>
180
+ </div>
181
+ <div className="ml-5 w-0 flex-1">
182
+ <dl>
183
+ <dt className="text-sm font-medium text-gray-500 truncate">Avg. Mastery</dt>
184
+ <dd className="text-2xl font-semibold text-gray-900">{classStats.averageMastery}%</dd>
185
+ </dl>
186
+ </div>
187
+ </div>
188
+ </div>
189
+ </div>
190
+
191
+ <div className="bg-white overflow-hidden shadow rounded-lg">
192
+ <div className="px-4 py-5 sm:p-6">
193
+ <div className="flex items-center">
194
+ <div className="flex-shrink-0 bg-red-500 rounded-md p-3">
195
+ <svg className="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
196
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-1.937-1-2.707.333-1.54 2.667-1.937 5.333-1.937 8z" />
197
+ </svg>
198
+ </div>
199
+ <div className="ml-5 w-0 flex-1">
200
+ <dl>
201
+ <dt className="text-sm font-medium text-gray-500 truncate">Struggling Students</dt>
202
+ <dd className="text-2xl font-semibold text-gray-900">{classStats.strugglingStudents}</dd>
203
+ </dl>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+ </div>
209
+
210
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
211
+ {/* Student List */}
212
+ <div className="bg-white shadow rounded-lg p-6">
213
+ <h2 className="text-xl font-semibold text-gray-800 mb-4">Student Progress</h2>
214
+
215
+ <div className="overflow-x-auto">
216
+ <table className="min-w-full divide-y divide-gray-200">
217
+ <thead className="bg-gray-50">
218
+ <tr>
219
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Student</th>
220
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Module</th>
221
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Mastery</th>
222
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
223
+ </tr>
224
+ </thead>
225
+ <tbody className="bg-white divide-y divide-gray-200">
226
+ {students.map((student) => (
227
+ <tr key={student.id}>
228
+ <td className="px-6 py-4 whitespace-nowrap">
229
+ <div className="text-sm font-medium text-gray-900">{student.name}</div>
230
+ </td>
231
+ <td className="px-6 py-4 whitespace-nowrap">
232
+ <div className="text-sm text-gray-500">{student.currentModule}</div>
233
+ </td>
234
+ <td className="px-6 py-4 whitespace-nowrap">
235
+ <div className="flex items-center">
236
+ <div className="w-24 bg-gray-200 rounded-full h-2.5 mr-2">
237
+ <div
238
+ className={`h-2.5 rounded-full ${
239
+ student.masteryPercentage >= 90 ? 'bg-blue-600' :
240
+ student.masteryPercentage >= 70 ? 'bg-green-500' :
241
+ student.masteryPercentage >= 40 ? 'bg-yellow-500' : 'bg-red-500'
242
+ }`}
243
+ style={{ width: `${student.masteryPercentage}%` }}
244
+ ></div>
245
+ </div>
246
+ <span className="text-sm text-gray-500">{student.masteryPercentage}%</span>
247
+ </div>
248
+ </td>
249
+ <td className="px-6 py-4 whitespace-nowrap">
250
+ <span className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${
251
+ student.status === 'active' ? 'bg-green-100 text-green-800' :
252
+ student.status === 'struggling' ? 'bg-red-100 text-red-800' : 'bg-gray-100 text-gray-800'
253
+ }`}>
254
+ {student.status.charAt(0).toUpperCase() + student.status.slice(1)}
255
+ </span>
256
+ </td>
257
+ </tr>
258
+ ))}
259
+ </tbody>
260
+ </table>
261
+ </div>
262
+ </div>
263
+
264
+ {/* Struggle Alerts */}
265
+ <div className="bg-white shadow rounded-lg p-6">
266
+ <h2 className="text-xl font-semibold text-gray-800 mb-4">Struggle Alerts</h2>
267
+
268
+ <div className="space-y-4">
269
+ {alerts.filter(a => !a.resolved).map((alert) => (
270
+ <div key={alert.id} className="border-l-4 border-red-500 bg-red-50 p-4 rounded">
271
+ <div className="flex justify-between">
272
+ <div>
273
+ <p className="font-medium text-red-800">{alert.studentName}</p>
274
+ <p className="text-sm text-red-600">{alert.issue}</p>
275
+ <p className="text-xs text-red-500">{alert.timestamp}</p>
276
+ </div>
277
+ <button
278
+ onClick={() => resolveAlert(alert.id)}
279
+ className="text-sm bg-red-500 hover:bg-red-600 text-white px-3 py-1 rounded-md"
280
+ >
281
+ Resolve
282
+ </button>
283
+ </div>
284
+ </div>
285
+ ))}
286
+
287
+ {alerts.filter(a => !a.resolved).length === 0 && (
288
+ <div className="text-center py-8 text-gray-500">
289
+ <p>No active struggle alerts</p>
290
+ </div>
291
+ )}
292
+ </div>
293
+
294
+ <div className="mt-6">
295
+ <h3 className="text-lg font-medium text-gray-800 mb-3">Generate Exercise</h3>
296
+ <div className="space-y-3">
297
+ <select className="w-full border border-gray-300 rounded-md px-3 py-2">
298
+ <option>Select student</option>
299
+ {students.filter(s => s.status === 'struggling').map(s => (
300
+ <option key={s.id} value={s.id}>{s.name}</option>
301
+ ))}
302
+ </select>
303
+ <textarea
304
+ className="w-full border border-gray-300 rounded-md px-3 py-2 h-24"
305
+ placeholder="Describe the custom exercise to generate..."
306
+ ></textarea>
307
+ <button className="w-full bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-md">
308
+ Generate Exercise
309
+ </button>
310
+ </div>
311
+ </div>
312
+ </div>
313
+ </div>
314
+ </main>
315
+ </div>
316
+ );
317
+ }
lib/api.ts ADDED
@@ -0,0 +1,387 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // API Service Layer for LearnFlow Frontend
2
+
3
+ const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
4
+
5
+ // Service URLs
6
+ const SERVICES = {
7
+ triage: process.env.NEXT_PUBLIC_TRIAGE_URL || 'http://localhost:8001',
8
+ concepts: process.env.NEXT_PUBLIC_CONCEPTS_URL || 'http://localhost:8002',
9
+ codeReview: process.env.NEXT_PUBLIC_CODE_REVIEW_URL || 'http://localhost:8003',
10
+ debug: process.env.NEXT_PUBLIC_DEBUG_URL || 'http://localhost:8004',
11
+ exercise: process.env.NEXT_PUBLIC_EXERCISE_URL || 'http://localhost:8005',
12
+ progress: process.env.NEXT_PUBLIC_PROGRESS_URL || 'http://localhost:8006',
13
+ };
14
+
15
+ // Auth token management
16
+ let authToken: string | null = null;
17
+
18
+ export const setAuthToken = (token: string) => {
19
+ authToken = token;
20
+ if (typeof window !== 'undefined') {
21
+ localStorage.setItem('learnflow_token', token);
22
+ }
23
+ };
24
+
25
+ export const getAuthToken = (): string | null => {
26
+ if (authToken) return authToken;
27
+ if (typeof window !== 'undefined') {
28
+ return localStorage.getItem('learnflow_token');
29
+ }
30
+ return null;
31
+ };
32
+
33
+ export const clearAuthToken = () => {
34
+ authToken = null;
35
+ if (typeof window !== 'undefined') {
36
+ localStorage.removeItem('learnflow_token');
37
+ }
38
+ };
39
+
40
+ // Generic fetch wrapper
41
+ async function apiFetch<T>(
42
+ url: string,
43
+ options: RequestInit = {}
44
+ ): Promise<T> {
45
+ const token = getAuthToken();
46
+
47
+ const headers: HeadersInit = {
48
+ 'Content-Type': 'application/json',
49
+ ...(token && { Authorization: `Bearer ${token}` }),
50
+ ...options.headers,
51
+ };
52
+
53
+ const response = await fetch(url, {
54
+ ...options,
55
+ headers,
56
+ });
57
+
58
+ if (!response.ok) {
59
+ const error = await response.json().catch(() => ({ message: 'Request failed' }));
60
+ throw new Error(error.message || `HTTP error! status: ${response.status}`);
61
+ }
62
+
63
+ return response.json();
64
+ }
65
+
66
+ // ==================== AUTH API ====================
67
+
68
+ export interface LoginRequest {
69
+ email: string;
70
+ password: string;
71
+ }
72
+
73
+ export interface RegisterRequest {
74
+ name: string;
75
+ email: string;
76
+ password: string;
77
+ role: 'student' | 'teacher';
78
+ }
79
+
80
+ export interface AuthResponse {
81
+ token: string;
82
+ user: {
83
+ id: string;
84
+ name: string;
85
+ email: string;
86
+ role: 'student' | 'teacher';
87
+ };
88
+ }
89
+
90
+ export const authAPI = {
91
+ login: async (data: LoginRequest): Promise<AuthResponse> => {
92
+ return apiFetch<AuthResponse>(`${API_BASE_URL}/auth/login`, {
93
+ method: 'POST',
94
+ body: JSON.stringify(data),
95
+ });
96
+ },
97
+
98
+ register: async (data: RegisterRequest): Promise<AuthResponse> => {
99
+ return apiFetch<AuthResponse>(`${API_BASE_URL}/auth/register`, {
100
+ method: 'POST',
101
+ body: JSON.stringify(data),
102
+ });
103
+ },
104
+
105
+ me: async (): Promise<AuthResponse['user']> => {
106
+ return apiFetch<AuthResponse['user']>(`${API_BASE_URL}/auth/me`);
107
+ },
108
+ };
109
+
110
+ // ==================== TRIAGE API ====================
111
+
112
+ export interface QueryRequest {
113
+ query: string;
114
+ user_id: string;
115
+ }
116
+
117
+ export interface RoutingResponse {
118
+ agent: string;
119
+ message: string;
120
+ params: Record<string, any>;
121
+ }
122
+
123
+ export const triageAPI = {
124
+ routeQuery: async (data: QueryRequest): Promise<RoutingResponse> => {
125
+ return apiFetch<RoutingResponse>(`${SERVICES.triage}/query`, {
126
+ method: 'POST',
127
+ body: JSON.stringify(data),
128
+ });
129
+ },
130
+
131
+ health: async (): Promise<{ status: string }> => {
132
+ return apiFetch<{ status: string }>(`${SERVICES.triage}/health`);
133
+ },
134
+ };
135
+
136
+ // ==================== CONCEPTS API ====================
137
+
138
+ export interface ExplainRequest {
139
+ topic: string;
140
+ level?: 'beginner' | 'intermediate' | 'advanced';
141
+ user_context?: Record<string, any>;
142
+ }
143
+
144
+ export interface ExplanationResponse {
145
+ topic: string;
146
+ explanation: string;
147
+ examples: string[];
148
+ level: string;
149
+ }
150
+
151
+ export const conceptsAPI = {
152
+ explain: async (data: ExplainRequest): Promise<ExplanationResponse> => {
153
+ return apiFetch<ExplanationResponse>(`${SERVICES.concepts}/explain`, {
154
+ method: 'POST',
155
+ body: JSON.stringify(data),
156
+ });
157
+ },
158
+
159
+ health: async (): Promise<{ status: string }> => {
160
+ return apiFetch<{ status: string }>(`${SERVICES.concepts}/health`);
161
+ },
162
+ };
163
+
164
+ // ==================== EXERCISE API ====================
165
+
166
+ export interface ExerciseRequest {
167
+ module: string;
168
+ topic: string;
169
+ difficulty?: 'beginner' | 'intermediate' | 'advanced';
170
+ user_id?: string;
171
+ }
172
+
173
+ export interface ExerciseResponse {
174
+ id: string;
175
+ module: string;
176
+ topic: string;
177
+ problem: string;
178
+ starter_code: string;
179
+ test_cases: Array<{ input: string; expected_output: string }>;
180
+ difficulty: string;
181
+ }
182
+
183
+ export interface SubmissionRequest {
184
+ quiz_id: string;
185
+ user_id: string;
186
+ code: string;
187
+ }
188
+
189
+ export interface GradeResponse {
190
+ quiz_id: string;
191
+ user_id: string;
192
+ score: number;
193
+ feedback: string;
194
+ passed_tests: number;
195
+ total_tests: number;
196
+ }
197
+
198
+ export const exerciseAPI = {
199
+ generate: async (data: ExerciseRequest): Promise<ExerciseResponse> => {
200
+ return apiFetch<ExerciseResponse>(`${SERVICES.exercise}/generate`, {
201
+ method: 'POST',
202
+ body: JSON.stringify(data),
203
+ });
204
+ },
205
+
206
+ grade: async (data: SubmissionRequest): Promise<GradeResponse> => {
207
+ return apiFetch<GradeResponse>(`${SERVICES.exercise}/grade`, {
208
+ method: 'POST',
209
+ body: JSON.stringify(data),
210
+ });
211
+ },
212
+
213
+ health: async (): Promise<{ status: string }> => {
214
+ return apiFetch<{ status: string }>(`${SERVICES.exercise}/health`);
215
+ },
216
+ };
217
+
218
+ // ==================== CODE REVIEW API ====================
219
+
220
+ export interface ReviewRequest {
221
+ code: string;
222
+ context?: string;
223
+ user_id?: string;
224
+ }
225
+
226
+ export interface ReviewResponse {
227
+ overall_quality: string;
228
+ issues: Array<{
229
+ type: string;
230
+ line: number;
231
+ message: string;
232
+ suggestion: string;
233
+ }>;
234
+ suggestions: string[];
235
+ score: number;
236
+ }
237
+
238
+ export const codeReviewAPI = {
239
+ review: async (data: ReviewRequest): Promise<ReviewResponse> => {
240
+ return apiFetch<ReviewResponse>(`${SERVICES.codeReview}/review`, {
241
+ method: 'POST',
242
+ body: JSON.stringify(data),
243
+ });
244
+ },
245
+
246
+ health: async (): Promise<{ status: string }> => {
247
+ return apiFetch<{ status: string }>(`${SERVICES.codeReview}/health`);
248
+ },
249
+ };
250
+
251
+ // ==================== DEBUG API ====================
252
+
253
+ export interface DebugRequest {
254
+ code: string;
255
+ error_message: string;
256
+ user_id?: string;
257
+ }
258
+
259
+ export interface DebugResponse {
260
+ error_type: string;
261
+ explanation: string;
262
+ fix_suggestion: string;
263
+ corrected_code: string;
264
+ learning_tip: string;
265
+ }
266
+
267
+ export const debugAPI = {
268
+ analyze: async (data: DebugRequest): Promise<DebugResponse> => {
269
+ return apiFetch<DebugResponse>(`${SERVICES.debug}/analyze`, {
270
+ method: 'POST',
271
+ body: JSON.stringify(data),
272
+ });
273
+ },
274
+
275
+ health: async (): Promise<{ status: string }> => {
276
+ return apiFetch<{ status: string }>(`${SERVICES.debug}/health`);
277
+ },
278
+ };
279
+
280
+ // ==================== PROGRESS API ====================
281
+
282
+ export interface ProgressData {
283
+ user_id: string;
284
+ overall_mastery: number;
285
+ modules_completed: number;
286
+ current_module: string;
287
+ modules: Record<string, Record<string, { mastery_score: number }>>;
288
+ }
289
+
290
+ export interface UpdateProgressRequest {
291
+ user_id: string;
292
+ module: string;
293
+ topic: string;
294
+ score: number;
295
+ activity_type: 'quiz' | 'exercise' | 'lesson';
296
+ }
297
+
298
+ export const progressAPI = {
299
+ getProgress: async (userId: string): Promise<ProgressData> => {
300
+ return apiFetch<ProgressData>(`${SERVICES.progress}/progress/${userId}`);
301
+ },
302
+
303
+ updateProgress: async (data: UpdateProgressRequest): Promise<ProgressData> => {
304
+ return apiFetch<ProgressData>(`${SERVICES.progress}/progress`, {
305
+ method: 'POST',
306
+ body: JSON.stringify(data),
307
+ });
308
+ },
309
+
310
+ health: async (): Promise<{ status: string }> => {
311
+ return apiFetch<{ status: string }>(`${SERVICES.progress}/health`);
312
+ },
313
+ };
314
+
315
+ // ==================== AI CHAT API ====================
316
+
317
+ export interface ChatMessage {
318
+ role: 'user' | 'assistant';
319
+ content: string;
320
+ }
321
+
322
+ export interface ChatRequest {
323
+ messages: ChatMessage[];
324
+ user_id: string;
325
+ context?: string;
326
+ }
327
+
328
+ export interface ChatResponse {
329
+ response: string;
330
+ agent_used: string;
331
+ }
332
+
333
+ export const chatAPI = {
334
+ sendMessage: async (data: ChatRequest): Promise<ChatResponse> => {
335
+ // First route through triage
336
+ const routing = await triageAPI.routeQuery({
337
+ query: data.messages[data.messages.length - 1].content,
338
+ user_id: data.user_id,
339
+ });
340
+
341
+ // Then call the appropriate agent
342
+ if (routing.agent === 'concepts-agent') {
343
+ const response = await conceptsAPI.explain({
344
+ topic: data.messages[data.messages.length - 1].content,
345
+ level: 'intermediate',
346
+ });
347
+ return {
348
+ response: `${response.explanation}\n\nExamples:\n${response.examples.join('\n')}`,
349
+ agent_used: routing.agent,
350
+ };
351
+ }
352
+
353
+ // Default response
354
+ return {
355
+ response: routing.message,
356
+ agent_used: routing.agent,
357
+ };
358
+ },
359
+ };
360
+
361
+ // ==================== UTILITY FUNCTIONS ====================
362
+
363
+ export const checkServicesHealth = async (): Promise<Record<string, boolean>> => {
364
+ const services = ['triage', 'concepts', 'codeReview', 'debug', 'exercise', 'progress'] as const;
365
+ const results: Record<string, boolean> = {};
366
+
367
+ await Promise.all(
368
+ services.map(async (service) => {
369
+ try {
370
+ const api = {
371
+ triage: triageAPI,
372
+ concepts: conceptsAPI,
373
+ codeReview: codeReviewAPI,
374
+ debug: debugAPI,
375
+ exercise: exerciseAPI,
376
+ progress: progressAPI,
377
+ }[service];
378
+ await api.health();
379
+ results[service] = true;
380
+ } catch {
381
+ results[service] = false;
382
+ }
383
+ })
384
+ );
385
+
386
+ return results;
387
+ };
next-env.d.ts ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+
4
+ // NOTE: This file should not be edited
5
+ // see https://nextjs.org/docs/basic-features/typescript for more information.
next.config.js ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('next').NextConfig} */
2
+ const nextConfig = {
3
+ experimental: {
4
+ // Enable SWC transforms for better dynamic import handling
5
+ swcPlugins: [],
6
+ },
7
+ // Handle dynamic imports properly
8
+ webpack: (config, { isServer }) => {
9
+ if (!isServer) {
10
+ // Allow dynamic imports in client-side bundles
11
+ config.resolve.fallback = {
12
+ ...config.resolve.fallback,
13
+ fs: false,
14
+ path: false,
15
+ os: false,
16
+ crypto: false,
17
+ stream: false,
18
+ buffer: false,
19
+ util: false,
20
+ };
21
+ }
22
+
23
+ // Configure chunk splitting for better loading
24
+ config.optimization.splitChunks = {
25
+ chunks: 'all',
26
+ cacheGroups: {
27
+ default: {
28
+ minChunks: 2,
29
+ priority: 20,
30
+ reuseExistingChunk: true,
31
+ },
32
+ vendor: {
33
+ test: /[\\/]node_modules[\\/]/,
34
+ name: 'vendors',
35
+ priority: 10,
36
+ chunks: 'all',
37
+ },
38
+ monaco: {
39
+ test: /[\\/]node_modules[\\/]monaco-editor/,
40
+ name: 'monaco',
41
+ priority: 30,
42
+ chunks: 'all',
43
+ },
44
+ },
45
+ };
46
+
47
+ return config;
48
+ },
49
+ };
50
+
51
+ module.exports = nextConfig;
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "learnflow-frontend",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "next lint"
10
+ },
11
+ "dependencies": {
12
+ "react": "^18",
13
+ "react-dom": "^18",
14
+ "next": "14.0.0",
15
+ "@monaco-editor/react": "^4.6.0",
16
+ "axios": "^1.5.0",
17
+ "clsx": "^2.0.0",
18
+ "tailwind-merge": "^1.14.0"
19
+ },
20
+ "devDependencies": {
21
+ "typescript": "^5",
22
+ "@types/node": "^20",
23
+ "@types/react": "^18",
24
+ "@types/react-dom": "^18",
25
+ "autoprefixer": "^10",
26
+ "postcss": "^8",
27
+ "tailwindcss": "^3",
28
+ "eslint-config-next": "14.0.0"
29
+ }
30
+ }
postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
tailwind.config.js ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ module.exports = {
3
+ content: [
4
+ './pages/**/*.{js,ts,jsx,tsx,mdx}',
5
+ './components/**/*.{js,ts,jsx,tsx,mdx}',
6
+ './app/**/*.{js,ts,jsx,tsx,mdx}',
7
+ ],
8
+ theme: {
9
+ extend: {
10
+ colors: {
11
+ // VeryWellMind-inspired wellness color palette
12
+ teal: {
13
+ 50: '#f0fdfa',
14
+ 100: '#ccfbf1',
15
+ 200: '#99f6e4',
16
+ 300: '#5eead4',
17
+ 400: '#2dd4bf',
18
+ 500: '#14b8a6',
19
+ 600: '#0d9488',
20
+ 700: '#0f766e',
21
+ 800: '#115e59',
22
+ 900: '#134e4a',
23
+ },
24
+ sage: {
25
+ 50: '#f6f7f4',
26
+ 100: '#e8ebe3',
27
+ 200: '#d4dac9',
28
+ 300: '#b5c0a5',
29
+ 400: '#96a67f',
30
+ 500: '#7a8b63',
31
+ 600: '#5f6e4c',
32
+ 700: '#4b573d',
33
+ 800: '#3e4734',
34
+ 900: '#353d2e',
35
+ },
36
+ lavender: {
37
+ 50: '#faf5ff',
38
+ 100: '#f3e8ff',
39
+ 200: '#e9d5ff',
40
+ 300: '#d8b4fe',
41
+ 400: '#c084fc',
42
+ 500: '#a855f7',
43
+ 600: '#9333ea',
44
+ 700: '#7e22ce',
45
+ 800: '#6b21a8',
46
+ 900: '#581c87',
47
+ },
48
+ cream: {
49
+ 50: '#fefdfb',
50
+ 100: '#fdf9f3',
51
+ 200: '#faf3e6',
52
+ 300: '#f5e9d4',
53
+ 400: '#eddbb8',
54
+ 500: '#e3c99a',
55
+ 600: '#d4b07a',
56
+ 700: '#c19660',
57
+ 800: '#a67b4b',
58
+ 900: '#8a6540',
59
+ },
60
+ coral: {
61
+ 50: '#fff5f5',
62
+ 100: '#ffe3e3',
63
+ 200: '#ffc9c9',
64
+ 300: '#ffa8a8',
65
+ 400: '#ff8787',
66
+ 500: '#ff6b6b',
67
+ 600: '#fa5252',
68
+ 700: '#f03e3e',
69
+ 800: '#e03131',
70
+ 900: '#c92a2a',
71
+ },
72
+ warmgray: {
73
+ 50: '#fafaf9',
74
+ 100: '#f5f5f4',
75
+ 200: '#e7e5e4',
76
+ 300: '#d6d3d1',
77
+ 400: '#a8a29e',
78
+ 500: '#78716c',
79
+ 600: '#57534e',
80
+ 700: '#44403c',
81
+ 800: '#292524',
82
+ 900: '#1c1917',
83
+ },
84
+ },
85
+ fontFamily: {
86
+ sans: ['Inter', 'system-ui', 'sans-serif'],
87
+ display: ['Georgia', 'serif'],
88
+ },
89
+ borderRadius: {
90
+ '4xl': '2rem',
91
+ '5xl': '2.5rem',
92
+ },
93
+ boxShadow: {
94
+ 'soft': '0 2px 15px -3px rgba(0, 0, 0, 0.07), 0 10px 20px -2px rgba(0, 0, 0, 0.04)',
95
+ 'soft-lg': '0 10px 40px -10px rgba(0, 0, 0, 0.1)',
96
+ 'inner-soft': 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.02)',
97
+ },
98
+ backgroundImage: {
99
+ 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
100
+ 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
101
+ 'wellness-gradient': 'linear-gradient(135deg, #f0fdfa 0%, #faf5ff 50%, #fdf9f3 100%)',
102
+ 'hero-pattern': 'radial-gradient(circle at 30% 20%, rgba(20, 184, 166, 0.1) 0%, transparent 50%)',
103
+ },
104
+ },
105
+ },
106
+ plugins: [],
107
+ }
tsconfig.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "lib": [
4
+ "dom",
5
+ "dom.iterable",
6
+ "esnext"
7
+ ],
8
+ "allowJs": true,
9
+ "skipLibCheck": true,
10
+ "strict": false,
11
+ "noEmit": true,
12
+ "incremental": true,
13
+ "esModuleInterop": true,
14
+ "module": "esnext",
15
+ "moduleResolution": "node",
16
+ "resolveJsonModule": true,
17
+ "isolatedModules": true,
18
+ "jsx": "preserve",
19
+ "plugins": [
20
+ {
21
+ "name": "next"
22
+ }
23
+ ]
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ ".next/types/**/*.ts",
28
+ "**/*.ts",
29
+ "**/*.tsx"
30
+ ],
31
+ "exclude": [
32
+ "node_modules"
33
+ ]
34
+ }
tsconfig.tsbuildinfo ADDED
@@ -0,0 +1 @@
 
 
1
+ {"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.es2024.d.ts","./node_modules/typescript/lib/lib.esnext.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2024.collection.d.ts","./node_modules/typescript/lib/lib.es2024.object.d.ts","./node_modules/typescript/lib/lib.es2024.promise.d.ts","./node_modules/typescript/lib/lib.es2024.regexp.d.ts","./node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2024.string.d.ts","./node_modules/typescript/lib/lib.esnext.array.d.ts","./node_modules/typescript/lib/lib.esnext.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.promise.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.esnext.iterator.d.ts","./node_modules/typescript/lib/lib.esnext.float16.d.ts","./node_modules/typescript/lib/lib.esnext.error.d.ts","./node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/next/dist/styled-jsx/types/css.d.ts","./node_modules/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/prop-types/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/shared/lib/amp.d.ts","./node_modules/next/amp.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/filereader.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.generated.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/next/dist/server/get-page-files.d.ts","./node_modules/@types/react/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/compiled/webpack/webpack.d.ts","./node_modules/next/dist/server/config.d.ts","./node_modules/next/dist/lib/load-custom-routes.d.ts","./node_modules/next/dist/shared/lib/image-config.d.ts","./node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/server/future/route-kind.d.ts","./node_modules/next/dist/server/future/route-definitions/route-definition.d.ts","./node_modules/next/dist/server/future/route-matches/route-match.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/server/config-shared.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/server/require-hook.d.ts","./node_modules/next/dist/server/node-polyfill-crypto.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/lib/revalidate.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/client/components/static-generation-async-storage.external.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/future/helpers/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","./node_modules/next/dist/server/web/spec-extension/cookies.d.ts","./node_modules/next/dist/server/web/spec-extension/request.d.ts","./node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/server/font-utils.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/server/future/route-modules/route-module.d.ts","./node_modules/next/dist/server/load-components.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/server/future/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/future/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/bloom-filter.d.ts","./node_modules/next/dist/shared/lib/router/router.d.ts","./node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","./node_modules/next/dist/server/future/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","./node_modules/next/dist/shared/lib/constants.d.ts","./node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","./node_modules/next/dist/build/webpack/loaders/next-app-loader.d.ts","./node_modules/next/dist/server/lib/app-dir-module.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/client/components/request-async-storage.external.d.ts","./node_modules/next/dist/server/app-render/create-error-handler.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/amp-context.shared-runtime.d.ts","./node_modules/next/dist/server/future/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/future/route-modules/app-page/module.compiled.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/router-reducer/create-initial-router-state.d.ts","./node_modules/next/dist/client/components/app-router.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/client/components/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/static-generation-bailout.d.ts","./node_modules/next/dist/client/components/static-generation-searchparams-bailout-provider.d.ts","./node_modules/next/dist/client/components/searchparams-bailout-proxy.d.ts","./node_modules/next/dist/server/app-render/rsc/preloads.d.ts","./node_modules/next/dist/server/app-render/rsc/taint.d.ts","./node_modules/next/dist/client/components/not-found-boundary.d.ts","./node_modules/next/dist/server/app-render/entry-base.d.ts","./node_modules/next/dist/build/templates/app-page.d.ts","./node_modules/next/dist/server/future/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/server/future/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/future/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/future/route-modules/pages/module.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/server/future/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/future/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/future/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/future/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/future/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/future/normalizers/normalizer.d.ts","./node_modules/next/dist/server/future/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/future/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/future/normalizers/request/postponed.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/lib/coalesced-function.d.ts","./node_modules/next/dist/trace/shared.d.ts","./node_modules/next/dist/trace/trace.d.ts","./node_modules/next/dist/trace/index.d.ts","./node_modules/next/dist/build/webpack-config.d.ts","./node_modules/next/dist/build/webpack/plugins/define-env-plugin.d.ts","./node_modules/next/dist/build/swc/index.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/server/dev/hot-reloader-types.d.ts","./node_modules/next/dist/telemetry/storage.d.ts","./node_modules/next/dist/server/lib/types.d.ts","./node_modules/next/dist/server/lib/router-utils/types.d.ts","./node_modules/next/dist/server/lib/render-server.d.ts","./node_modules/next/dist/server/lib/router-server.d.ts","./node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","./node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","./node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/types/index.d.ts","./node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","./node_modules/@next/env/dist/index.d.ts","./node_modules/next/dist/shared/lib/utils.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate-path.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate-tag.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/shared/lib/runtime-config.external.d.ts","./node_modules/next/config.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/navigation.d.ts","./node_modules/next/navigation.d.ts","./node_modules/next/router.d.ts","./node_modules/next/dist/client/script.d.ts","./node_modules/next/script.d.ts","./node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/server.d.ts","./node_modules/next/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/index.d.ts","./node_modules/next/image-types/global.d.ts","./next-env.d.ts","./app/layout.tsx","./.next/types/app/layout.ts","./app/page.tsx","./.next/types/app/page.ts","./app/register/page.tsx","./.next/types/app/register/page.ts","./app/student/chat/page.tsx","./.next/types/app/student/chat/page.ts","./app/student/dashboard/page.tsx","./.next/types/app/student/dashboard/page.ts","./node_modules/monaco-editor/esm/vs/editor/editor.api.d.ts","./node_modules/@monaco-editor/loader/lib/types.d.ts","./node_modules/monaco-editor/esm/vs/editor/editor.main.d.ts","./node_modules/@monaco-editor/react/dist/index.d.ts","./app/student/learn/page.tsx","./.next/types/app/student/learn/page.ts","./app/student/progress/page.tsx","./.next/types/app/student/progress/page.ts","./app/student/quiz/page.tsx","./.next/types/app/student/quiz/page.ts","./app/teacher/dashboard/page.tsx","./.next/types/app/teacher/dashboard/page.ts","./node_modules/@types/json5/index.d.ts","./node_modules/@types/trusted-types/lib/index.d.ts","./node_modules/@types/trusted-types/index.d.ts"],"fileIdsList":[[99,145,342,389],[99,145,342,391],[99,145,342,393],[99,145,342,395],[99,145,342,397],[99,145,342,403],[99,145,342,405],[99,145,342,407],[99,145,342,409],[99,145,386],[87,99,145,369,373],[87,99,145,359,402],[99,145,386,387],[99,145,399],[87,99,145,399,400,401],[99,145],[99,142,145],[99,144,145],[145],[99,145,150,178],[99,145,146,151,156,164,175,186],[99,145,146,147,156,164],[94,95,96,99,145],[99,145,148,187],[99,145,149,150,157,165],[99,145,150,175,183],[99,145,151,153,156,164],[99,144,145,152],[99,145,153,154],[99,145,155,156],[99,144,145,156],[99,145,156,157,158,175,186],[99,145,156,157,158,171,175,178],[99,145,153,156,159,164,175,186],[99,145,156,157,159,160,164,175,183,186],[99,145,159,161,175,183,186],[97,98,99,100,101,102,103,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192],[99,145,156,162],[99,145,163,186,191],[99,145,153,156,164,175],[99,145,165],[99,145,166],[99,144,145,167],[99,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192],[99,145,169],[99,145,170],[99,145,156,171,172],[99,145,171,173,187,189],[99,145,156,175,176,178],[99,145,177,178],[99,145,175,176],[99,145,178],[99,145,179],[99,142,145,175,180],[99,145,156,181,182],[99,145,181,182],[99,145,150,164,175,183],[99,145,184],[99,145,164,185],[99,145,159,170,186],[99,145,150,187],[99,145,175,188],[99,145,163,189],[99,145,190],[99,140,145],[99,140,145,156,158,167,175,178,186,189,191],[99,145,175,192],[87,99,145,197,198,199],[87,99,145,197,198],[87,99,145],[87,91,99,145,196,343,382],[87,91,99,145,195,343,382],[84,85,86,99,145],[99,145,412],[92,99,145],[99,145,347],[99,145,349,350,351,352],[99,145,354],[99,145,202,211,218,343],[99,145,202,209,213,220],[99,145,211,320],[99,145,268,278,291,385],[99,145,299],[99,145,202,211,217,255,265,318,385],[99,145,217,385],[99,145,211,265,266,385],[99,145,211,217,255,385],[99,145,385],[99,145,217,218,385],[99,144,145,193],[87,99,145,279,280,296],[87,99,145,196],[87,99,145,279,294],[99,145,275,297,370,371],[99,145,232],[99,144,145,193,232,269,270,271],[87,99,145,294,297],[99,145,294,296],[87,99,145,294,295,297],[99,144,145,193,212,225,226],[87,99,145,203,364],[87,99,145,186,193],[87,99,145,217,253],[87,99,145,217],[99,145,251,256],[87,99,145,252,346],[87,91,99,145,159,193,195,196,343,380,381],[99,145,201],[99,145,336,337,338,339,340,341],[99,145,338],[87,99,145,344,346],[87,99,145,346],[99,145,159,193,212,346],[99,145,159,193,210,227,228,243,272,273,293,294],[99,145,226,227,272,281,282,283,284,285,286,287,288,289,290,385],[87,99,145,170,193,211,225,243,245,247,293,343,385],[99,145,159,193,212,213,232,233,269],[99,145,159,193,211,213],[99,145,159,175,193,210,212,213],[99,145,159,170,186,193,201,203,210,211,212,213,217,220,222,224,225,228,229,237,239,242,243,245,246,247,294,302,304,307,309,310,311,343],[99,145,159,175,193],[99,145,202,203,204,210,343,346,385],[99,145,211],[99,145,159,175,186,193,207,319,321,322,385],[99,145,170,186,193,207,210,212,225,236,237,239,240,241,245,307,312,314,332,333],[99,145,211,215,225],[99,145,210,211],[99,145,229,308],[99,145,308],[99,145,206,207],[99,145,206,248],[99,145,206],[99,145,208,229,306],[99,145,305],[99,145,207,208],[99,145,208,303],[99,145,207],[99,145,293],[99,145,159,193,210,228,244,263,268,274,277,292,294],[99,145,257,258,259,260,261,262,275,276,297,344],[99,145,301],[99,145,159,193,210,228,244,249,298,300,302,343,346],[99,145,159,186,193,203,210,211,224],[99,145,267],[99,145,159,193,325,331],[99,145,222,224,346],[99,145,326,332,335],[99,145,159,215,325,327],[99,145,202,211,222,246,329],[99,145,159,193,211,217,246,315,323,324,328,329,330],[99,145,194,243,244,343,346],[99,145,159,170,186,193,208,210,212,215,219,220,222,224,225,228,236,237,239,240,241,242,245,304,312,313,346],[99,145,159,193,210,211,215,314,334],[99,145,159,193,220,227],[87,99,145,159,170,193,201,203,210,213,228,242,243,245,247,301,343,346],[99,145,159,170,186,193,205,208,209,212],[99,145,223],[99,145,159,193,220,228],[99,145,159,193,211,229],[99,145,159,193],[99,145,231],[99,145,233],[99,145,211,230,232,236],[99,145,211,230,232],[99,145,159,193,205,211,212,233,234,235],[87,99,145,294,295,296],[99,145,264],[87,99,145,203],[87,99,145,239],[87,99,145,194,242,247,343,346],[99,145,203,364,365],[87,99,145,256],[87,99,145,170,186,193,201,250,252,254,255,346],[99,145,212,217,239],[99,145,170,193],[99,145,238],[87,99,145,157,159,170,193,201,256,265,343,344,345],[83,87,88,89,90,99,145,195,196,343,382],[99,145,150],[99,145,316,317],[99,145,316],[99,145,356],[99,145,358],[99,145,360],[99,145,362],[99,145,366],[91,93,99,145,343,348,353,355,357,359,361,363,367,369,373,374,376,383,384,385],[99,145,368],[99,145,372],[99,145,252],[99,145,375],[99,144,145,233,234,235,236,377,378,379,382],[99,145,193],[87,91,99,145,159,161,170,193,195,196,197,199,201,213,335,342,346,382],[99,112,116,145,186],[99,112,145,175,186],[99,107,145],[99,109,112,145,183,186],[99,145,164,183],[99,107,145,193],[99,109,112,145,164,186],[99,104,105,108,111,145,156,175,186],[99,112,119,145],[99,104,110,145],[99,112,133,134,145],[99,108,112,145,178,186,193],[99,133,145,193],[99,106,107,145,193],[99,112,145],[99,106,107,108,109,110,111,112,113,114,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,134,135,136,137,138,139,145],[99,112,127,145],[99,112,119,120,145],[99,110,112,120,121,145],[99,111,145],[99,104,107,112,145],[99,112,116,120,121,145],[99,116,145],[99,110,112,115,145,186],[99,104,109,112,119,145],[99,145,175],[99,107,112,133,145,191,193]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"2ab096661c711e4a81cc464fa1e6feb929a54f5340b46b0a07ac6bbf857471f0","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"60037901da1a425516449b9a20073aa03386cce92f7a1fd902d7602be3a7c2e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22adec94ef7047a6c9d1af3cb96be87a335908bf9ef386ae9fd50eeb37f44c47","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"73f78680d4c08509933daf80947902f6ff41b6230f94dd002ae372620adb0f60","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5239f5c01bcfa9cd32f37c496cf19c61d69d37e48be9de612b541aac915805b","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"0990a7576222f248f0a3b888adcb7389f957928ce2afb1cd5128169086ff4d29","impliedFormat":1},{"version":"eb5b19b86227ace1d29ea4cf81387279d04bb34051e944bc53df69f58914b788","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"87d9d29dbc745f182683f63187bf3d53fd8673e5fca38ad5eaab69798ed29fbc","impliedFormat":1},{"version":"7a3aa194cfd5919c4da251ef04ea051077e22702638d4edcb9579e9101653519","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc69795d9954ee4ad57545b10c7bf1a7260d990231b1685c147ea71a6faa265c","impliedFormat":1},{"version":"8bc6c94ff4f2af1f4023b7bb2379b08d3d7dd80c698c9f0b07431ea16101f05f","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"57194e1f007f3f2cbef26fa299d4c6b21f4623a2eddc63dfeef79e38e187a36e","impliedFormat":1},{"version":"0f6666b58e9276ac3a38fdc80993d19208442d6027ab885580d93aec76b4ef00","impliedFormat":1},{"version":"05fd364b8ef02fb1e174fbac8b825bdb1e5a36a016997c8e421f5fab0a6da0a0","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"2cbe0621042e2a68c7cbce5dfed3906a1862a16a7d496010636cdbdb91341c0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"2fd4c143eff88dabb57701e6a40e02a4dbc36d5eb1362e7964d32028056a782b","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"0e456fd5b101271183d99a9087875a282323e3a3ff0d7bcf1881537eaa8b8e63","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"0225ecb9ed86bdb7a2c7fd01f1556906902929377b44483dc4b83e03b3ef227d","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"ddc734b4fae82a01d247e9e342d020976640b5e93b4e9b3a1e30e5518883a060","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"05db535df8bdc30d9116fe754a3473d1b6479afbc14ae8eb18b605c62677d518","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"8caa5c86be1b793cd5f599e27ecb34252c41e011980f7d61ae4989a149ff6ccc","impliedFormat":1},{"version":"91b0f6d01993021ecbe01eb076db6a3cf1b66359c1d99104f43436010e81afb5","impliedFormat":1},{"version":"d1bd4e51810d159899aad1660ccb859da54e27e08b8c9862b40cd36c1d9ff00f","impliedFormat":1},{"version":"17ed71200119e86ccef2d96b73b02ce8854b76ad6bd21b5021d4269bec527b5f","impliedFormat":1},{"version":"1cfa8647d7d71cb03847d616bd79320abfc01ddea082a49569fda71ac5ece66b","impliedFormat":1},{"version":"bb7a61dd55dc4b9422d13da3a6bb9cc5e89be888ef23bbcf6558aa9726b89a1c","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"cfe4ef4710c3786b6e23dae7c086c70b4f4835a2e4d77b75d39f9046106e83d3","impliedFormat":1},{"version":"cbea99888785d49bb630dcbb1613c73727f2b5a2cf02e1abcaab7bcf8d6bf3c5","impliedFormat":1},{"version":"3b8f725c3d5ffb64bf876c87409686875102c6f7450b268d8f5188b6920f7c25","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"2dad084c67e649f0f354739ec7df7c7df0779a28a4f55c97c6b6883ae850d1ce","impliedFormat":1},{"version":"fa5bbc7ab4130dd8cdc55ea294ec39f76f2bc507a0f75f4f873e38631a836ca7","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"cf86de1054b843e484a3c9300d62fbc8c97e77f168bbffb131d560ca0474d4a8","impliedFormat":1},{"version":"37f7b8e560025858aae5195ca74a3e95ecd55591e2babc0acd57bc1dab4ea8ea","impliedFormat":1},{"version":"e2d5483c9a79900ba9d6012135f18b662b3ca1d33fde4f5e39b71f74e47d6331","impliedFormat":1},{"version":"22b9fab85e85b95f6378b5a2bd43c9d2e15106d760e0e58111c416fe224cc76f","impliedFormat":1},{"version":"fc46f093d1b754a8e3e34a071a1dd402f42003927676757a9a10c6f1d195a35b","impliedFormat":1},{"version":"b7b3258e8d47333721f9d4c287361d773f8fa88e52d1148812485d9fc06d2577","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"49e567e0aa388ab416eeb7a7de9bce5045a7b628bad18d1f6fa9d3eacee7bc3f","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"87eaecac33864ecec8972b1773c5d897f0f589deb7ac8fe0dcdf4b721b06e28d","impliedFormat":1},{"version":"47e5af2a841356a961f815e7c55d72554db0c11b4cba4d0caab91f8717846a94","impliedFormat":1},{"version":"4c91cc1ab59b55d880877ccf1999ded0bb2ebc8e3a597c622962d65bf0e76be8","impliedFormat":1},{"version":"fa1ea09d3e073252eccff2f6630a4ce5633cc2ff963ba672dd8fd6783108ea83","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"309816cd6e597f4d4b080bc5e36215c6b78196f744d578adf61589bee5fd7eea","impliedFormat":1},{"version":"bdb44eca306ff5b62bcf2b4e70e96a40987e018029d95565e2f234aad80830cf","impliedFormat":1},{"version":"edaa0bbf2891b17f904a67aef7f9d53371c993fe3ff6dec708c2aff6083b01af","impliedFormat":1},{"version":"89aece12f9cd6d736ae7c350800f257a2363f6322ae8f998da73153fb405d8af","impliedFormat":1},{"version":"d23518a5f155f1a3e07214baf0295687507122ae2e6e9bd5e772551ebd4b3157","impliedFormat":1},{"version":"aa9a92be255ec97f669ea89678fafcbd35d165f65b68ff22685263f6eaeb3c9c","impliedFormat":1},{"version":"fa8b514302736759e491d3df074a61f54ed1a6a69b4aadee05dbcdda53f881c3","impliedFormat":1},{"version":"e8da637cbd6ed1cf6c36e9424f6bcee4515ca2c677534d4006cbd9a05f930f0c","impliedFormat":1},{"version":"ca1b882a105a1972f82cc58e3be491e7d750a1eb074ffd13b198269f57ed9e1b","impliedFormat":1},{"version":"c9d71f340f1a4576cd2a572f73a54dc7212161fa172dfe3dea64ac627c8fcb50","impliedFormat":1},{"version":"3867ca0e9757cc41e04248574f4f07b8f9e3c0c2a796a5eb091c65bfd2fc8bdb","impliedFormat":1},{"version":"6c66f6f7d9ff019a644ff50dd013e6bf59be4bf389092948437efa6b77dc8f9a","impliedFormat":1},{"version":"4e10622f89fea7b05dd9b52fb65e1e2b5cbd96d4cca3d9e1a60bb7f8a9cb86a1","impliedFormat":1},{"version":"ef2d1bd01d144d426b72db3744e7a6b6bb518a639d5c9c8d86438fb75a3b1934","impliedFormat":1},{"version":"b9750fe7235da7d8bf75cb171bf067b7350380c74271d3f80f49aea7466b55b5","impliedFormat":1},{"version":"ac60bbee0d4235643cc52b57768b22de8c257c12bd8c2039860540cab1fa1d82","impliedFormat":1},{"version":"973b59a17aaa817eb205baf6c132b83475a5c0a44e8294a472af7793b1817e89","impliedFormat":1},{"version":"ada39cbb2748ab2873b7835c90c8d4620723aedf323550e8489f08220e477c7f","impliedFormat":1},{"version":"6e5f5cee603d67ee1ba6120815497909b73399842254fc1e77a0d5cdc51d8c9c","impliedFormat":1},{"version":"f79e0681538ef94c273a46bb1a073b4fe9fdc93ef7f40cc2c3abd683b85f51fc","impliedFormat":1},{"version":"70f3814c457f54a7efe2d9ce9d2686de9250bb42eb7f4c539bd2280a42e52d33","impliedFormat":1},{"version":"17ace83a5bea3f1da7e0aef7aab0f52bca22619e243537a83a89352a611b837d","impliedFormat":1},{"version":"ef61792acbfa8c27c9bd113f02731e66229f7d3a169e3c1993b508134f1a58e0","impliedFormat":1},{"version":"6cf2d240d4e449ccfee82aff7ce0fd1890c1b6d4f144ec003aa51f7f70f68935","impliedFormat":1},{"version":"f6404e7837b96da3ea4d38c4f1a3812c96c9dcdf264e93d5bdb199f983a3ef4b","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1dc574e42493e8bf9bb37be44d9e38c5bd7bbc04f884e5e58b4d69636cb192b3","impliedFormat":1},{"version":"9deab571c42ed535c17054f35da5b735d93dc454d83c9a5330ecc7a4fb184e9e","affectsGlobalScope":true,"impliedFormat":1},{"version":"db01d18853469bcb5601b9fc9826931cc84cc1a1944b33cad76fd6f1e3d8c544","affectsGlobalScope":true,"impliedFormat":1},{"version":"6b8e8c0331a0c2e9fb53b8b0d346e44a8db8c788dae727a2c52f4cf3bd857f0d","impliedFormat":1},{"version":"903e299a28282fa7b714586e28409ed73c3b63f5365519776bf78e8cf173db36","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"dd3900b24a6a8745efeb7ad27629c0f8a626470ac229c1d73f1fe29d67e44dca","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"ec29be0737d39268696edcec4f5e97ce26f449fa9b7afc2f0f99a86def34a418","impliedFormat":1},{"version":"8945919709e0c6069c32ca26a675a0de90fd2ad70d5bc3ba281c628729a0c39d","impliedFormat":1},{"version":"ec6cba1c02c675e4dd173251b156792e8d3b0c816af6d6ad93f1a55d674591aa","impliedFormat":1},{"version":"763ee3998716d599321e34b7f7e93a8e57bef751206325226ebf088bf75ea460","impliedFormat":1},{"version":"e15d3c84d5077bb4a3adee4c791022967b764dc41cb8fa3cfa44d4379b2c95f5","impliedFormat":1},{"version":"3556cfbab7b43da96d15a442ddbb970e1f2fc97876d055b6555d86d7ac57dae5","impliedFormat":1},{"version":"437751e0352c6e924ddf30e90849f1d9eb00ca78c94d58d6a37202ec84eb8393","impliedFormat":1},{"version":"48e8af7fdb2677a44522fd185d8c87deff4d36ee701ea003c6c780b1407a1397","impliedFormat":1},{"version":"606e6f841ba9667de5d83ca458449f0ed8c511ba635f753eaa731e532dea98c7","impliedFormat":1},{"version":"7c0d4fc71fe32cedb758c7e3c08715235a51e5a22d184306a59dae10a9c7ffaa","impliedFormat":1},{"version":"ce8a0b21e80cf5f10adc9336b46ffc666696d1373a763b170baf69a722f85d67","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"13283350547389802aa35d9f2188effaeac805499169a06ef5cd77ce2a0bd63f","impliedFormat":1},{"version":"680793958f6a70a44c8d9ae7d46b7a385361c69ac29dcab3ed761edce1c14ab8","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"baeffe1b7d836196d497eb755699718deb729a2033078a018f037a14ecaeb9a7","impliedFormat":1},{"version":"39da0a8478aede3a55308089e231c5966b2196e7201494280b1e19f8ec8e24d4","impliedFormat":1},{"version":"90be1a7f573bad71331ff10deeadce25b09034d3d27011c2155bcb9cb9800b7f","impliedFormat":1},{"version":"bc7221c9a8dc71587ff784120f7707985627282dad0a99439e893a1588651ef0","impliedFormat":1},{"version":"438c7513b1df91dcef49b13cd7a1c4720f91a36e88c1df731661608b7c055f10","impliedFormat":1},{"version":"ad444a874f011d3a797f1a41579dbfcc6b246623f49c20009f60e211dbd5315e","impliedFormat":1},{"version":"1124613ba0669e7ea5fb785ede1c3f254ed1968335468b048b8fc35c172393de","impliedFormat":1},{"version":"5fa139523e35fd907f3dd6c2e38ef2066687b27ed88e2680783e05662355ac04","impliedFormat":1},{"version":"9c250db4bab4f78fad08be7f4e43e962cc143e0f78763831653549ceb477344a","impliedFormat":1},{"version":"9385cdc09850950bc9b59cca445a3ceb6fcca32b54e7b626e746912e489e535e","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"db7c948e2e69559324be7628cb63296ec8986d60f26173f9e324aeb8a2fe23d8","impliedFormat":1},{"version":"9c2353ef1fb353a1c8f30af2cf104f0bc64ebc2fcdb98c2834d451bd654664ab","impliedFormat":1},{"version":"63a8e96f65a22604eae82737e409d1536e69a467bb738bec505f4f97cce9d878","impliedFormat":1},{"version":"3fd78152a7031315478f159c6a5872c712ece6f01212c78ea82aef21cb0726e2","impliedFormat":1},{"version":"7fda4c0e3f50513286029633c458ee82cee563cd6af20b92e43b4425c969c146","impliedFormat":1},{"version":"cda4052f66b1e6cb7cf1fdfd96335d1627aa24a3b8b82ba4a9f873ec3a7bcde8","impliedFormat":1},{"version":"703733dde084b7e856f5940f9c3c12007ca62858accb9482c2b65e030877702d","impliedFormat":1},{"version":"413cb597cc5933562ec064bfb1c3a9164ef5d2f09e5f6b7bd19f483d5352449e","impliedFormat":1},{"version":"fd933f824347f9edd919618a76cdb6a0c0085c538115d9a287fa0c7f59957ab3","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"6a1aa3e55bdc50503956c5cd09ae4cd72e3072692d742816f65c66ca14f4dfdd","impliedFormat":1},{"version":"ab75cfd9c4f93ffd601f7ca1753d6a9d953bbedfbd7a5b3f0436ac8a1de60dfa","impliedFormat":1},{"version":"6cc79183c88040697e1552ba81c5245b0c701b965623774587c4b9d1e7497278","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"1364f64d2fb03bbb514edc42224abd576c064f89be6a990136774ecdd881a1da","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"950fb67a59be4c2dbe69a5786292e60a5cb0e8612e0e223537784c731af55db1","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"07ca44e8d8288e69afdec7a31fa408ce6ab90d4f3d620006701d5544646da6aa","impliedFormat":1},{"version":"82c27d4cf380b0e6cd62628f069b850298d20051f0b7b0a1904fdb38c53fa7a6","impliedFormat":1},{"version":"c97b9278c8ce212c1bdf4fae9c77d58c15565d4ebf663d761a9deb924b6ca8b3","impliedFormat":1},{"version":"8bb6e7ce91ec84336203e87010b1198514548c2e44789752c1741eaac02f2431","impliedFormat":1},{"version":"b33ac7d8d7d1bfc8cc06c75d1ee186d21577ab2026f482e29babe32b10b26512","impliedFormat":1},{"version":"24f8f342c14c911eedfee43074c6a0d0a5ebb5ec984353bffaeadddb3f6a6b1c","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"03d4a10c21ac451b682246f3261b769247baf774c4878551c02256ae98299b1c","impliedFormat":1},{"version":"2d9b710fee8c3d7eabee626af8fd6ec2cf6f71e6b7429b307b8f67d70b1707c5","impliedFormat":1},{"version":"652a4bbefba6aa309bfc3063f59ed1a2e739c1d802273b0e6e0aa7082659f3b3","impliedFormat":1},{"version":"d7ca19bfb1ba4c3ef59d43bd7cd3719d8c5ffb60a9b6f402dee4e229f4d921aa","impliedFormat":1},{"version":"0c0a85a19b60f2ec18a32ff051bb1423860977a16b645dbf159baa7202bc633b","impliedFormat":1},{"version":"fc5bdc1d13667041055811568043956c75150923d8b9a32b989ac7588418ce47","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"d3b290cc3c08cbde2b463df2616b948fb32733dafe3ac29b9e6ded26baee5489","impliedFormat":1},{"version":"94404c4a878fe291e7578a2a80264c6f18e9f1933fbb57e48f0eb368672e389c","impliedFormat":1},{"version":"5c1b7f03aa88be854bc15810bfd5bd5a1943c5a7620e1c53eddd2a013996343e","impliedFormat":1},{"version":"f416c9c3eee9d47ff49132c34f96b9180e50485d435d5748f0e8b72521d28d2e","impliedFormat":1},{"version":"9558d365d0e72b6d9bd8c1742fe1185f983965c6d2eff88a117a59b9f51d3c5f","impliedFormat":1},{"version":"6cc2961fbe8d32e34fd4c7f1b7045353016fff50df98bc31af7c7d1b4b6eb552","impliedFormat":1},{"version":"01aa917531e116485beca44a14970834687b857757159769c16b228eb1e49c5f","impliedFormat":1},{"version":"a2e1f7010ae5f746b937621840cb87dee9eeb69188d32880bd9752029084212c","impliedFormat":1},{"version":"dd30eb34b5c4597a568de0efb8b34e328c224648c258759ac541beb16256ffb6","impliedFormat":1},{"version":"6129bd7098131a0e346352901bc8d461a76d0568686bb0e1f8499df91fde8a1f","impliedFormat":1},{"version":"7cd7923a36835c1194a92b808068a524c4e7c0ff7bdc8712865800e6963d75da","impliedFormat":1},{"version":"82200d39d66c91f502f74c85db8c7a8d56cfc361c20d7da6d7b68a4eeaaefbf4","impliedFormat":1},{"version":"741067675daa6d4334a2dc80a4452ca3850e89d5852e330db7cb2b5f867173b1","impliedFormat":1},{"version":"a1c8542ed1189091dd39e732e4390882a9bcd15c0ca093f6e9483eba4e37573f","impliedFormat":1},{"version":"131b1475d2045f20fb9f43b7aa6b7cb51f25250b5e4c6a1d4aa3cf4dd1a68793","impliedFormat":1},{"version":"3a17f09634c50cce884721f54fd9e7b98e03ac505889c560876291fcf8a09e90","impliedFormat":1},{"version":"32531dfbb0cdc4525296648f53b2b5c39b64282791e2a8c765712e49e6461046","impliedFormat":1},{"version":"0ce1b2237c1c3df49748d61568160d780d7b26693bd9feb3acb0744a152cd86d","impliedFormat":1},{"version":"e489985388e2c71d3542612685b4a7db326922b57ac880f299da7026a4e8a117","impliedFormat":1},{"version":"76264a4df0b7c78b7b12dfaedc05d9f1016f27be1f3d0836417686ff6757f659","impliedFormat":1},{"version":"c0fabd699e6e0b6bfc1728c048e52737b73fb6609eeeae0f7f4775ff14ff2df6","affectsGlobalScope":true,"impliedFormat":1},{"version":"fd1b9d883b9446f1e1da1e1033a6a98995c25fbf3c10818a78960e2f2917d10c","impliedFormat":1},{"version":"19252079538942a69be1645e153f7dbbc1ef56b4f983c633bf31fe26aeac32cd","impliedFormat":1},{"version":"4dd4f6e28afc1ee30ce76ffc659d19e14dff29cb19b7747610ada3535b7409af","impliedFormat":1},{"version":"1640728521f6ab040fc4a85edd2557193839d0cd0e41c02004fc8d415363d4e2","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"ec9fd890d681789cb0aa9efbc50b1e0afe76fbf3c49c3ac50ff80e90e29c6bcb","impliedFormat":1},{"version":"5fbd292aa08208ae99bf06d5da63321fdc768ee43a7a104980963100a3841752","impliedFormat":1},{"version":"9eac5a6beea91cfb119688bf44a5688b129b804ede186e5e2413572a534c21bb","impliedFormat":1},{"version":"e81bf06c0600517d8f04cc5de398c28738bfdf04c91fb42ad835bfe6b0d63a23","impliedFormat":1},{"version":"363996fe13c513a7793aa28ffb05b5d0230db2b3d21b7bfaf21f79e4cde54b4e","impliedFormat":1},{"version":"b7fff2d004c5879cae335db8f954eb1d61242d9f2d28515e67902032723caeab","impliedFormat":1},{"version":"5f3dc10ae646f375776b4e028d2bed039a93eebbba105694d8b910feebbe8b9c","impliedFormat":1},{"version":"7f6c48cacd08c1b1e29737b8221b7661e6b855767f8778f9a181fa2f74c09d21","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"15959543f93f27e8e2b1a012fe28e14b682034757e2d7a6c1f02f87107fc731e","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"4e828bf688597c32905215785730cbdb603b54e284d472a23fc0195c6d4aeee8","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"4da80db9ed5a1a20fd5bfce863dd178b8928bcaf4a3d75e8657bcae32e572ede","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"f72ee46ae3f73e6c5ff0da682177251d80500dd423bfd50286124cd0ca11e160","impliedFormat":1},{"version":"898b714aad9cfd0e546d1ad2c031571de7622bd0f9606a499bee193cf5e7cf0c","impliedFormat":1},{"version":"d707fb7ca32930495019a4c85500385f6850c785ee0987a1b6bcad6ade95235e","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"5d26aae738fa3efc87c24f6e5ec07c54694e6bcf431cc38d3da7576d6bb35bd6","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"e0aa1079d58134e55ad2f73508ad1be565a975f2247245d76c64c1ca9e5e5b26","impliedFormat":1},{"version":"cd0c5af42811a4a56a0f77856cfa6c170278e9522888db715b11f176df3ff1f2","impliedFormat":1},{"version":"68f81dad9e8d7b7aa15f35607a70c8b68798cf579ac44bd85325b8e2f1fb3600","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"94fd3ce628bd94a2caf431e8d85901dbe3a64ab52c0bd1dbe498f63ca18789f7","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"c0eeaaa67c85c3bb6c52b629ebbfd3b2292dc67e8c0ffda2fc6cd2f78dc471e6","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"2470a2412a59c6177cd4408dd7edb099ca7ace68c0187f54187dfee56dc9c5aa","impliedFormat":99},{"version":"c2008605e78208cfa9cd70bd29856b72dda7ad89df5dc895920f8e10bcb9cd0a","impliedFormat":99},{"version":"ec61ebac4d71c4698318673efbb5c481a6c4d374da8d285f6557541a5bd318d0","impliedFormat":99},{"version":"16fd66ae997b2f01c972531239da90fbf8ab4022bb145b9587ef746f6cecde5a","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc8fbee8f73bf5ffd6ba08ba1c554d6f714c49cae5b5e984afd545ab1b7abe06","affectsGlobalScope":true,"impliedFormat":1},{"version":"3586f5ea3cc27083a17bd5c9059ede9421d587286d5a47f4341a4c2d00e4fa91","impliedFormat":1},{"version":"521fc35a732f1a19f5d52024c2c22e257aa63258554968f7806a823be2f82b03","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},"9269d492817e359123ac64c8205e5d05dab63d71a3a7a229e68b5d9a0e8150bf","9036ae3ed72f744b33643af8e52b6e920bad5000534ddb5783c0b9f48f69d1c9","13fe295414f8fb40f00c222881b4cdf0bd7307292581b68793a657365b82f2a3","773719ba9c61d8d214621803d5b4789224dda790582e69dfa7e8a7863fee6c0c","593bba908bc1947c33f4b527d20dcedc96fa87e953b082e4667f8e8272154bc4","1457b7757cde4056b3008434882ea1c18ec5f7c61150b4f33b44a45fcf4cdf55","ff0236b46656604f1ab88d7e6cfe4cb399f5f70534b59f4c4684f0937389c404","7f2a3c03c8d709b1d8df85c3c7c586d84047351c70b17dd31c25d10545e4a36f","9acdf9ba116b4ea4215a8750fcd976324d30846da9e1ab419ff0a11098c4ee7a","5339f80c9aeada565c03c138854229837d15f5df2cef981b061565b06810828a","0b2eb709a02f1a688daa3929f579acec0b413f983d5c019ccdf951cb5b2bd8e5",{"version":"b99c4ff8d11110b9699edc4e5c3bb304360a70ca47e4f9851fc42ad0b663ba83","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e5c41e56098ae93bc42a15473acb1a176f28b2ba95c38f3c67820434acd85b6","impliedFormat":1},{"version":"ba340fc8e5b0f08d90c6ef8552b8ce7bb5dc8e18d47b57f90dee105bc77d0d9e","affectsGlobalScope":true,"impliedFormat":1},{"version":"0f263eeea7877199808b1bc220df95b25a72695ec214eb96d740d4b06c7cc868","impliedFormat":1},"d0e134d21c26b531a5dbe6d801b7b7a6409129926713b18fe0ab5efec2789c1c","c873123a6480c3cd533524bfdea0bf7871bb7d549abc3b6252d59de1bf2ed3cf","9e19240df6ed90533e9a734fad6084dd3801347b81e153169411c275c4a6c6c9","56062695918e75372afd67333c94642091525272ecc6378839069e37ec6802ba","626efb23ccea0f0c727d061cb5ba2b90aa17678bacf7672c7c2871dbbd6d89f4","98908f00c2992f073cf6e78988bc734a0f6f717fd9c17450ba0a42e2e7ff5fb6","9586ec947eac461551939a20205e2d7390447340d78225faa9bc8ccfa590237b","7c8dbc5f184cb9834a27e42081f4f6b35d3f77045ac959f72f60c9e4af05c6b8",{"version":"96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","impliedFormat":1},{"version":"15fe687c59d62741b4494d5e623d497d55eb38966ecf5bea7f36e48fc3fbe15e","impliedFormat":1},{"version":"2c3b8be03577c98530ef9cb1a76e2c812636a871f367e9edf4c5f3ce702b77f8","affectsGlobalScope":true,"impliedFormat":1}],"root":[[388,398],[403,410]],"options":{"allowJs":true,"esModuleInterop":true,"jsx":1,"module":99,"skipLibCheck":true,"strict":false},"referencedMap":[[390,1],[392,2],[394,3],[396,4],[398,5],[404,6],[406,7],[408,8],[410,9],[389,10],[391,11],[393,11],[395,11],[397,11],[403,12],[405,11],[407,11],[409,11],[388,13],[400,14],[402,15],[345,16],[411,16],[142,17],[143,17],[144,18],[99,19],[145,20],[146,21],[147,22],[94,16],[97,23],[95,16],[96,16],[148,24],[149,25],[150,26],[151,27],[152,28],[153,29],[154,29],[155,30],[156,31],[157,32],[158,33],[100,16],[98,16],[159,34],[160,35],[161,36],[193,37],[162,38],[163,39],[164,40],[165,41],[166,42],[167,43],[168,44],[169,45],[170,46],[171,47],[172,47],[173,48],[174,16],[175,49],[177,50],[176,51],[178,52],[179,53],[180,54],[181,55],[182,56],[183,57],[184,58],[185,59],[186,60],[187,61],[188,62],[189,63],[190,64],[101,16],[102,16],[103,16],[141,65],[191,66],[192,67],[86,16],[198,68],[199,69],[197,70],[195,71],[196,72],[84,16],[87,73],[413,74],[412,16],[85,16],[399,16],[401,14],[93,75],[348,76],[353,77],[355,78],[217,79],[222,80],[321,81],[292,82],[300,83],[319,84],[218,85],[266,16],[267,86],[320,87],[243,88],[219,89],[247,88],[237,88],[204,88],[284,90],[209,16],[281,91],[279,92],[226,16],[282,93],[372,94],[290,70],[371,16],[370,95],[283,70],[272,96],[280,97],[295,98],[296,99],[287,16],[227,100],[285,16],[286,70],[365,101],[368,102],[254,103],[253,104],[252,105],[375,70],[251,106],[231,16],[378,16],[381,16],[380,70],[382,107],[200,16],[315,16],[202,108],[336,16],[337,16],[339,16],[342,109],[338,16],[340,110],[341,110],[221,16],[347,106],[356,111],[360,112],[213,113],[274,114],[273,16],[291,115],[288,16],[289,16],[294,116],[270,117],[212,118],[241,119],[312,120],[205,121],[211,122],[201,123],[323,124],[334,125],[322,16],[333,126],[242,16],[229,127],[309,128],[308,16],[311,129],[310,129],[263,130],[248,130],[303,131],[249,131],[207,132],[206,16],[307,133],[306,134],[305,135],[304,136],[208,137],[278,138],[293,139],[277,140],[299,141],[301,142],[298,140],[244,137],[194,16],[313,143],[268,144],[332,145],[225,146],[327,147],[220,16],[328,148],[330,149],[331,150],[326,16],[325,121],[245,151],[314,152],[335,153],[214,16],[216,16],[228,154],[302,155],[210,156],[215,16],[224,157],[223,158],[230,159],[271,160],[269,95],[232,161],[234,162],[379,16],[233,163],[235,164],[350,16],[351,16],[349,16],[352,16],[377,16],[236,165],[276,70],[92,16],[297,166],[255,16],[265,167],[358,70],[364,168],[262,70],[362,70],[261,169],[344,170],[260,168],[203,16],[366,171],[258,70],[259,70],[250,16],[264,16],[257,172],[256,173],[246,174],[240,175],[329,16],[239,176],[238,16],[354,16],[275,70],[346,177],[83,16],[91,178],[88,70],[89,16],[90,16],[324,179],[318,180],[316,16],[317,181],[357,182],[359,183],[361,184],[363,185],[387,186],[367,186],[386,187],[369,188],[373,189],[374,190],[376,191],[383,192],[385,16],[384,193],[343,194],[81,16],[82,16],[13,16],[14,16],[16,16],[15,16],[2,16],[17,16],[18,16],[19,16],[20,16],[21,16],[22,16],[23,16],[24,16],[3,16],[25,16],[26,16],[4,16],[27,16],[31,16],[28,16],[29,16],[30,16],[32,16],[33,16],[34,16],[5,16],[35,16],[36,16],[37,16],[38,16],[6,16],[42,16],[39,16],[40,16],[41,16],[43,16],[7,16],[44,16],[49,16],[50,16],[45,16],[46,16],[47,16],[48,16],[8,16],[54,16],[51,16],[52,16],[53,16],[55,16],[9,16],[56,16],[57,16],[58,16],[60,16],[59,16],[61,16],[62,16],[10,16],[63,16],[64,16],[65,16],[11,16],[66,16],[67,16],[68,16],[69,16],[70,16],[1,16],[71,16],[72,16],[12,16],[76,16],[74,16],[79,16],[78,16],[73,16],[77,16],[75,16],[80,16],[119,195],[129,196],[118,195],[139,197],[110,198],[109,199],[138,193],[132,200],[137,201],[112,202],[126,203],[111,204],[135,205],[107,206],[106,193],[136,207],[108,208],[113,209],[114,16],[117,209],[104,16],[140,210],[130,211],[121,212],[122,213],[124,214],[120,215],[123,216],[133,193],[115,217],[116,218],[125,219],[105,220],[128,211],[127,209],[131,16],[134,221]],"affectedFilesPendingEmit":[390,392,394,396,398,404,406,408,410,389,391,393,395,397,403,405,407,409],"version":"5.9.3"}