Spaces:
Running
Running
Download src/components/certification-flow/CourseSelection.tsx from Sarvesh213/getcert-backend: direct link, hf CLI and curl.
- Browser
- Download file 11.6 kB
-
https://huggingface.co/spaces/Sarvesh213/getcert-backend/resolve/main/src/components/certification-flow/CourseSelection.tsx
- Command line
-
hf download hf://spaces/Sarvesh213/getcert-backend/src/components/certification-flow/CourseSelection.tsx
-
curl -L -o CourseSelection.tsx https://huggingface.co/spaces/Sarvesh213/getcert-backend/resolve/main/src/components/certification-flow/CourseSelection.tsx
11.6 kB
| import { useState } from 'react'; | |
| import type { CertificationTrack } from '../../types/getcertV2'; | |
| import { | |
| ArrowLeft, | |
| ArrowRight, | |
| Shield, | |
| TrendingUp, | |
| CheckCircle2, | |
| ClipboardList, | |
| PenTool | |
| } from 'lucide-react'; | |
| import { resolveCanonicalCourseTitle } from '../../utils/courseTitleResolver'; | |
| interface CourseSelectionProps { | |
| onCourseSelect: (courseName: string, category?: string) => void; | |
| loading: boolean; | |
| onBackToDashboard: () => void; | |
| certificationTrack?: CertificationTrack | null; | |
| } | |
| export function CourseSelection({ | |
| onCourseSelect, | |
| loading, | |
| onBackToDashboard, | |
| certificationTrack | |
| }: CourseSelectionProps) { | |
| const [customCourse, setCustomCourse] = useState(''); | |
| const [selectedCategory, setSelectedCategory] = useState<string | null>(null); | |
| // Popular course recommendations | |
| const recommendedCourses = [ | |
| { name: 'JavaScript Fundamentals', category: 'Programming', popularity: 95 }, | |
| { name: 'HTML & CSS Basics', category: 'Web Development', popularity: 92 }, | |
| { name: 'Git & Version Control', category: 'Developer Tools', popularity: 88 }, | |
| { name: 'Python Basics', category: 'Programming', popularity: 90 }, | |
| { name: 'WordPress Basics', category: 'CMS', popularity: 85 }, | |
| { name: 'Basic SQL', category: 'Databases', popularity: 87 }, | |
| { name: 'Graphic Design Basics', category: 'Design', popularity: 94 }, | |
| { name: 'UI / UX Design', category: 'Design', popularity: 96 }, | |
| { name: 'Digital Marketing', category: 'Marketing', popularity: 83 }, | |
| { name: 'Photoshop Basics', category: 'Design', popularity: 80 } | |
| ]; | |
| const categories = [ | |
| { name: 'Programming', count: 25 }, | |
| { name: 'Web Development', count: 18 }, | |
| { name: 'Design', count: 15 }, | |
| { name: 'Marketing', count: 12 }, | |
| { name: 'Developer Tools', count: 10 } | |
| ]; | |
| const handleCourseSubmit = () => { | |
| if (customCourse.trim()) { | |
| const canonical = resolveCanonicalCourseTitle(customCourse.trim()); | |
| onCourseSelect(canonical); | |
| } | |
| }; | |
| const handleKeyPress = (e: React.KeyboardEvent) => { | |
| if (e.key === 'Enter' && !loading) { | |
| handleCourseSubmit(); | |
| } | |
| }; | |
| const filteredCourses = selectedCategory | |
| ? recommendedCourses.filter(course => course.category === selectedCategory) | |
| : recommendedCourses; | |
| return ( | |
| <div className="bg-slate-50 min-h-full text-slate-900 font-sans transition-colors duration-200"> | |
| <div className="max-w-4xl mx-auto px-4 sm:px-6 py-6 sm:py-8 pb-16"> | |
| {/* Header */} | |
| <div className="text-center mb-8"> | |
| <div className="flex justify-start mb-4"> | |
| <button | |
| onClick={onBackToDashboard} | |
| className="inline-flex items-center gap-2 text-xs font-semibold text-slate-600 hover:text-slate-900 transition-colors px-3 py-1.5 rounded-lg bg-white border border-slate-200 shadow-2xs cursor-pointer" | |
| > | |
| <ArrowLeft className="w-3.5 h-3.5" /> | |
| <span>Back to Dashboard</span> | |
| </button> | |
| </div> | |
| <h1 className="text-2xl sm:text-4xl font-extrabold tracking-tight text-slate-900 mb-2"> | |
| Select Course or Enter Any Technical Domain | |
| </h1> | |
| <p className="text-xs sm:text-sm text-slate-500 max-w-2xl mx-auto leading-relaxed"> | |
| Enter any technical topic or skill to generate your syllabus, or choose from our curated courses below. | |
| </p> | |
| </div> | |
| {/* Custom Course Input Scratchpad */} | |
| <div className="bg-white rounded-2xl border border-slate-200/90 p-5 sm:p-7 mb-8 shadow-xs"> | |
| <div className="flex items-center space-x-2 mb-3"> | |
| <PenTool className="w-4 h-4 text-[#132F50]" /> | |
| <h2 className="text-sm font-bold text-slate-900"> | |
| Enter Any Technical Skill | |
| </h2> | |
| </div> | |
| <div className="flex flex-col sm:flex-row gap-3"> | |
| <input | |
| type="text" | |
| value={customCourse} | |
| onChange={(e) => setCustomCourse(e.target.value)} | |
| onKeyPress={handleKeyPress} | |
| placeholder="e.g. React 19, Distributed Systems, Rust Systems, Machine Learning..." | |
| className="flex-1 px-4 py-2.5 bg-slate-50 border border-slate-300 rounded-lg text-sm text-slate-900 focus:outline-none focus:border-[#132F50] focus:ring-2 focus:ring-[#132F50]/20 transition-all" | |
| disabled={loading} | |
| /> | |
| <button | |
| onClick={handleCourseSubmit} | |
| disabled={!customCourse.trim() || loading} | |
| className="px-5 py-2.5 bg-[#132F50] hover:bg-[#0e233d] text-white font-semibold text-xs tracking-wide rounded-lg shadow-xs flex items-center justify-center gap-2 disabled:opacity-50 transition-all cursor-pointer active:scale-[0.98]" | |
| > | |
| {loading ? ( | |
| <> | |
| <span className="w-3.5 h-3.5 border-2 border-white border-t-transparent rounded-full animate-spin"></span> | |
| <span>Preparing Curriculum...</span> | |
| </> | |
| ) : ( | |
| <span>Start Curriculum</span> | |
| )} | |
| </button> | |
| </div> | |
| </div> | |
| {/* Categories */} | |
| <div className="mb-6"> | |
| <h3 className="text-xs font-semibold uppercase tracking-wider text-slate-700 mb-3"> | |
| Domain Categories | |
| </h3> | |
| <div className="flex flex-wrap gap-2"> | |
| <button | |
| onClick={() => setSelectedCategory(null)} | |
| className={`px-3.5 py-1.5 rounded-full text-xs font-semibold transition-all cursor-pointer ${ | |
| selectedCategory === null | |
| ? 'bg-[#132F50] text-white shadow-2xs' | |
| : 'bg-white text-slate-700 border border-slate-200 hover:bg-slate-100' | |
| }`} | |
| > | |
| All Categories | |
| </button> | |
| {categories.map((category) => ( | |
| <button | |
| key={category.name} | |
| onClick={() => setSelectedCategory(category.name)} | |
| className={`px-3.5 py-1.5 rounded-full text-xs font-semibold transition-all flex items-center gap-1.5 cursor-pointer ${ | |
| selectedCategory === category.name | |
| ? 'bg-[#132F50] text-white shadow-2xs' | |
| : 'bg-white text-slate-700 border border-slate-200 hover:bg-slate-100' | |
| }`} | |
| > | |
| <span>{category.name}</span> | |
| <span className="text-[10px] opacity-75">({category.count})</span> | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| {/* Recommended Courses Grid */} | |
| <div className="bg-white rounded-2xl border border-slate-200/90 p-6 shadow-xs mb-8"> | |
| <div className="flex items-center justify-between pb-3 mb-4 border-b border-slate-100"> | |
| <h3 className="text-base font-bold text-slate-900"> | |
| {selectedCategory ? `${selectedCategory} Syllabi` : 'Accredited Curricula'} | |
| </h3> | |
| <span className="text-xs text-blue-700 font-semibold flex items-center gap-1 bg-blue-50 px-2.5 py-0.5 rounded-full border border-blue-100"> | |
| <CheckCircle2 className="w-3.5 h-3.5 text-blue-600" /> | |
| <span>Transcript Grounded</span> | |
| </span> | |
| </div> | |
| <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> | |
| {filteredCourses.map((course, index) => { | |
| const canonicalName = resolveCanonicalCourseTitle(course.name); | |
| return ( | |
| <button | |
| key={index} | |
| onClick={() => onCourseSelect(canonicalName, course.category)} | |
| disabled={loading} | |
| className="p-4 text-left bg-slate-50/70 hover:bg-blue-50/40 rounded-xl border border-slate-200/80 hover:border-[#132F50]/40 transition-all flex flex-col justify-between h-[155px] group cursor-pointer" | |
| > | |
| <div className="flex items-start justify-between w-full"> | |
| <span className="text-[10px] font-semibold text-slate-600 uppercase tracking-wider px-2 py-0.5 rounded bg-white border border-slate-200"> | |
| {course.category} | |
| </span> | |
| <div className="text-[11px] font-semibold text-slate-500 flex items-center gap-1"> | |
| <TrendingUp className="w-3 h-3 text-emerald-600" /> | |
| <span>{course.popularity}% rating</span> | |
| </div> | |
| </div> | |
| <h4 className="font-bold text-slate-900 tracking-tight text-sm line-clamp-2 mt-2"> | |
| {canonicalName} | |
| </h4> | |
| <div className="flex items-center justify-between w-full border-t border-slate-200/60 pt-2 text-xs font-semibold text-[#132F50] group-hover:text-blue-700"> | |
| <span>Enroll Syllabus</span> | |
| <ArrowRight className="w-3.5 h-3.5 transition-transform group-hover:translate-x-1" /> | |
| </div> | |
| </button> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| {/* Info Section */} | |
| <div className="bg-white rounded-2xl border border-slate-200/90 p-6 shadow-xs"> | |
| <div className="flex items-center gap-2 mb-4"> | |
| <ClipboardList className="w-4 h-4 text-[#132F50]" /> | |
| <h3 className="text-xs font-bold text-slate-700 uppercase tracking-wider"> | |
| Certification Workflow | |
| </h3> | |
| </div> | |
| <div className="divide-y divide-slate-100 sm:divide-y-0 sm:flex sm:items-start sm:justify-between sm:gap-6 text-xs"> | |
| <div className="flex items-start space-x-3 py-3 sm:py-0 flex-1"> | |
| <span className="w-6 h-6 rounded-full bg-blue-50 text-[#132F50] font-bold text-xs flex items-center justify-center shrink-0 border border-blue-200/60">1</span> | |
| <div className="space-y-0.5"> | |
| <div className="font-bold text-slate-900 text-xs">Learning Modules</div> | |
| <div className="text-slate-500 leading-relaxed font-normal">Review core concepts with concise takeaways and practical code examples.</div> | |
| </div> | |
| </div> | |
| <div className="flex items-start space-x-3 py-3 sm:py-0 flex-1"> | |
| <span className="w-6 h-6 rounded-full bg-blue-50 text-[#132F50] font-bold text-xs flex items-center justify-center shrink-0 border border-blue-200/60">2</span> | |
| <div className="space-y-0.5"> | |
| <div className="font-bold text-slate-900 text-xs">Assessment</div> | |
| <div className="text-slate-500 leading-relaxed font-normal">Complete a comprehensive evaluation aligned directly with the curriculum.</div> | |
| </div> | |
| </div> | |
| <div className="flex items-start space-x-3 py-3 sm:py-0 flex-1"> | |
| <span className="w-6 h-6 rounded-full bg-blue-50 text-[#132F50] font-bold text-xs flex items-center justify-center shrink-0 border border-blue-200/60">3</span> | |
| <div className="space-y-0.5"> | |
| <div className="font-bold text-slate-900 text-xs">Official Certificate</div> | |
| <div className="text-slate-500 leading-relaxed font-normal">Receive your verified certificate with instant QR validation and PDF download.</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |