425 lines
17 KiB
TypeScript
425 lines
17 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { Card, CardContent, CardHeader, CardTitle } from './ui/card';
|
|
import { Button } from './ui/button';
|
|
import { Progress } from './ui/progress';
|
|
import { Badge } from './ui/badge';
|
|
import {
|
|
ChevronRight,
|
|
ChevronDown,
|
|
ChevronUp,
|
|
Check,
|
|
Play,
|
|
Calendar,
|
|
Clock,
|
|
BookOpen,
|
|
Video,
|
|
Target,
|
|
User,
|
|
Award,
|
|
Users
|
|
} from 'lucide-react';
|
|
|
|
// Mock program data
|
|
interface ProgramData {
|
|
id: string;
|
|
title: string;
|
|
subtitle: string;
|
|
description: string;
|
|
duration: string;
|
|
level: string;
|
|
progress: number;
|
|
totalCourses: number;
|
|
completedCourses: number;
|
|
category: string;
|
|
instructor: {
|
|
name: string;
|
|
title: string;
|
|
bio: string;
|
|
avatar: string;
|
|
};
|
|
courses: ProgramCourse[];
|
|
learningOutcomes: string[];
|
|
thumbnail: string;
|
|
}
|
|
|
|
interface ProgramCourse {
|
|
id: string;
|
|
title: string;
|
|
duration: string;
|
|
isCompleted: boolean;
|
|
isActive: boolean;
|
|
progress: number;
|
|
description: string;
|
|
}
|
|
|
|
const programDatabase: Record<string, ProgramData> = {
|
|
'program-1': {
|
|
id: 'program-1',
|
|
title: 'Executive Leadership Development Program',
|
|
subtitle: 'Comprehensive Leadership Transformation',
|
|
description: 'An intensive 12-week program designed to transform mid-level managers into strategic leaders. This comprehensive program covers essential leadership competencies, strategic thinking, and organizational transformation skills.',
|
|
duration: '12 weeks',
|
|
level: 'Advanced',
|
|
progress: 42,
|
|
totalCourses: 6,
|
|
completedCourses: 2,
|
|
category: 'Leadership Development',
|
|
instructor: {
|
|
name: 'Dr. Sarah Williams',
|
|
title: 'Executive Leadership Expert',
|
|
bio: 'Dr. Williams has over 20 years of experience in executive coaching and leadership development, having worked with Fortune 100 companies.',
|
|
avatar: 'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?w=100&h=100&fit=crop'
|
|
},
|
|
thumbnail: 'https://images.unsplash.com/photo-1552664730-d307ca884978?w=800&h=450&fit=crop',
|
|
learningOutcomes: [
|
|
'Develop strategic leadership vision and execution capabilities',
|
|
'Master advanced communication and influence techniques',
|
|
'Build high-performance teams and organizational culture',
|
|
'Navigate complex business challenges and drive transformation'
|
|
],
|
|
courses: [
|
|
{
|
|
id: 'course-1',
|
|
title: 'Strategic Leadership Foundations',
|
|
duration: '2 weeks',
|
|
isCompleted: true,
|
|
isActive: false,
|
|
progress: 100,
|
|
description: 'Core principles of strategic leadership and vision development'
|
|
},
|
|
{
|
|
id: 'course-2',
|
|
title: 'Advanced Communication & Influence',
|
|
duration: '2 weeks',
|
|
isCompleted: true,
|
|
isActive: false,
|
|
progress: 100,
|
|
description: 'Mastering executive communication and stakeholder influence'
|
|
},
|
|
{
|
|
id: 'course-3',
|
|
title: 'Building High-Performance Teams',
|
|
duration: '2 weeks',
|
|
isCompleted: false,
|
|
isActive: true,
|
|
progress: 67,
|
|
description: 'Team dynamics, culture building, and performance optimization'
|
|
},
|
|
{
|
|
id: 'course-4',
|
|
title: 'Change Management & Innovation',
|
|
duration: '2 weeks',
|
|
isCompleted: false,
|
|
isActive: false,
|
|
progress: 0,
|
|
description: 'Leading organizational change and fostering innovation'
|
|
},
|
|
{
|
|
id: 'course-5',
|
|
title: 'Financial Acumen for Leaders',
|
|
duration: '2 weeks',
|
|
isCompleted: false,
|
|
isActive: false,
|
|
progress: 0,
|
|
description: 'Understanding financial metrics and business strategy'
|
|
},
|
|
{
|
|
id: 'course-6',
|
|
title: 'Executive Capstone Project',
|
|
duration: '2 weeks',
|
|
isCompleted: false,
|
|
isActive: false,
|
|
progress: 0,
|
|
description: 'Applied leadership project with real business impact'
|
|
}
|
|
]
|
|
}
|
|
};
|
|
|
|
interface ProgramDetailPageProps {
|
|
programId: string;
|
|
onNavigateBack: () => void;
|
|
}
|
|
|
|
export function ProgramDetailPage({ programId, onNavigateBack }: ProgramDetailPageProps) {
|
|
const [programData] = useState<ProgramData>(programDatabase[programId] || programDatabase['program-1']);
|
|
const [expandedCourse, setExpandedCourse] = useState<string | null>(null);
|
|
|
|
const toggleCourse = (courseId: string) => {
|
|
setExpandedCourse(expandedCourse === courseId ? null : courseId);
|
|
};
|
|
|
|
return (
|
|
<div className="h-full bg-background">
|
|
{/* Breadcrumb Navigation - Full Width */}
|
|
<div className="bg-background border-b border-border py-3">
|
|
<div className="px-6">
|
|
<nav className="flex items-center gap-2 text-[14px] text-muted-foreground">
|
|
<button
|
|
onClick={onNavigateBack}
|
|
className="hover:text-[var(--color-brand-primary)] transition-colors"
|
|
>
|
|
Library
|
|
</button>
|
|
<ChevronRight className="h-3 w-3" />
|
|
<span>{programData.category}</span>
|
|
<ChevronRight className="h-3 w-3" />
|
|
<span className="text-foreground font-medium">Programs</span>
|
|
<ChevronRight className="h-3 w-3" />
|
|
<span className="text-foreground font-medium">{programData.title}</span>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Program Header - Full Width */}
|
|
<div className="bg-background border-b border-border py-6">
|
|
<div className="px-6">
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex-1">
|
|
<div className="flex items-center gap-3 mb-2">
|
|
<Badge variant="secondary" className="bg-[var(--color-brand-primary)]/10 text-[var(--color-brand-primary)] border-[var(--color-brand-primary)]/20">
|
|
Program
|
|
</Badge>
|
|
<Badge variant="outline" className="text-[12px]">
|
|
{programData.level}
|
|
</Badge>
|
|
</div>
|
|
<h1 className="text-[28px] font-bold leading-[34px] tracking-[-1px] mb-2 text-gray-900">
|
|
{programData.title}
|
|
</h1>
|
|
<p className="text-[16px] text-muted-foreground mb-3">
|
|
{programData.subtitle} • {programData.duration}
|
|
</p>
|
|
<div className="flex items-center gap-4 text-[14px] text-muted-foreground">
|
|
<div className="flex items-center gap-1">
|
|
<BookOpen className="h-4 w-4" />
|
|
<span>{programData.completedCourses}/{programData.totalCourses} courses completed</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
<Clock className="h-4 w-4" />
|
|
<span>{programData.duration}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<div className="text-right">
|
|
<p className="text-[14px] text-muted-foreground">Overall Progress</p>
|
|
<p className="text-[24px] font-bold text-[var(--color-brand-primary)]">{programData.progress}%</p>
|
|
</div>
|
|
<div className="w-12 h-12 rounded-full bg-[var(--color-brand-primary)] flex items-center justify-center relative">
|
|
<div
|
|
className="w-8 h-8 rounded-full bg-[var(--color-brand-accent)]"
|
|
style={{
|
|
clipPath: `inset(0 ${100 - programData.progress}% 0 0)`
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Content Layout */}
|
|
<div className="flex h-full">
|
|
{/* Left Sidebar - Program Structure */}
|
|
<aside className="w-[300px] flex-shrink-0 bg-white border-r border-border">
|
|
<div className="h-full overflow-y-auto">
|
|
<div className="p-6">
|
|
<h3 className="text-[16px] font-semibold text-foreground mb-6">Program Structure</h3>
|
|
|
|
<div className="space-y-4">
|
|
{programData.courses.map((course, index) => (
|
|
<div key={course.id} className="mb-4">
|
|
<div
|
|
className="flex items-center justify-between mb-3 cursor-pointer hover:bg-gray-50 p-3 rounded-lg border border-border"
|
|
onClick={() => toggleCourse(course.id)}
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<div className={`w-8 h-8 rounded-full flex items-center justify-center ${
|
|
course.isCompleted
|
|
? 'bg-[#21A36A]'
|
|
: course.isActive
|
|
? 'bg-[var(--color-brand-primary)]'
|
|
: 'bg-gray-200'
|
|
}`}>
|
|
{course.isCompleted ? (
|
|
<Check className="h-4 w-4 text-white" />
|
|
) : (
|
|
<span className="text-[12px] font-medium text-white">{index + 1}</span>
|
|
)}
|
|
</div>
|
|
<div className="flex-1">
|
|
<h4 className="text-[14px] font-medium text-foreground">
|
|
{course.title}
|
|
</h4>
|
|
<p className="text-[12px] text-muted-foreground">
|
|
{course.duration}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{expandedCourse === course.id ? (
|
|
<ChevronUp className="h-4 w-4 text-muted-foreground" />
|
|
) : (
|
|
<ChevronDown className="h-4 w-4 text-muted-foreground" />
|
|
)}
|
|
</div>
|
|
|
|
{expandedCourse === course.id && (
|
|
<div className="ml-11 mb-3">
|
|
<p className="text-[13px] text-muted-foreground mb-3">
|
|
{course.description}
|
|
</p>
|
|
{!course.isCompleted && (
|
|
<div className="mb-3">
|
|
<div className="flex items-center justify-between mb-1">
|
|
<span className="text-[12px] text-muted-foreground">Progress</span>
|
|
<span className="text-[12px] text-[var(--color-brand-primary)]">{course.progress}%</span>
|
|
</div>
|
|
<Progress value={course.progress} className="h-2" />
|
|
</div>
|
|
)}
|
|
<Button
|
|
size="sm"
|
|
className="w-full"
|
|
variant={course.isCompleted ? "outline" : "default"}
|
|
>
|
|
{course.isCompleted ? "Review" : course.isActive ? "Continue" : "Start Course"}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
{/* Main Content */}
|
|
<main className="flex-1 min-w-0">
|
|
<div className="p-6">
|
|
{/* Program Overview */}
|
|
<div className="mb-8">
|
|
<h2 className="text-[20px] font-semibold text-foreground mb-4">Program Overview</h2>
|
|
<img
|
|
src={programData.thumbnail}
|
|
alt={programData.title}
|
|
className="w-full h-64 object-cover rounded-lg mb-4"
|
|
/>
|
|
<p className="text-[16px] text-muted-foreground leading-relaxed">
|
|
{programData.description}
|
|
</p>
|
|
</div>
|
|
|
|
{/* Learning Outcomes */}
|
|
<div className="mb-8">
|
|
<h3 className="text-[20px] font-semibold text-foreground mb-4">What you'll achieve</h3>
|
|
<div className="space-y-3">
|
|
{programData.learningOutcomes.map((outcome, index) => (
|
|
<div key={index} className="flex items-start gap-3">
|
|
<div className="w-5 h-5 rounded-full bg-[#21A36A] flex items-center justify-center flex-shrink-0 mt-0.5">
|
|
<Check className="h-3 w-3 text-white" />
|
|
</div>
|
|
<p className="text-[16px] text-foreground">
|
|
{outcome}
|
|
</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Program Leader */}
|
|
<div>
|
|
<h3 className="text-[20px] font-semibold text-foreground mb-4">Program Leader</h3>
|
|
<div className="flex items-start gap-4 p-4 bg-muted/50 rounded-lg">
|
|
<img
|
|
src={programData.instructor.avatar}
|
|
alt={programData.instructor.name}
|
|
className="w-16 h-16 rounded-full object-cover"
|
|
/>
|
|
<div>
|
|
<h4 className="text-[18px] font-semibold text-foreground">{programData.instructor.name}</h4>
|
|
<p className="text-[16px] text-[var(--color-brand-primary)] mb-2">{programData.instructor.title}</p>
|
|
<p className="text-[16px] text-muted-foreground">{programData.instructor.bio}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
{/* Right Sidebar - Program Plan */}
|
|
<aside className="w-[300px] flex-shrink-0 bg-white border-l border-border">
|
|
<div className="h-full overflow-y-auto">
|
|
<div className="p-6">
|
|
<h3 className="text-[18px] font-semibold text-foreground mb-4">Program plan</h3>
|
|
|
|
<p className="text-[14px] text-muted-foreground mb-6">
|
|
I'm committed to completing this program in 12 weeks.
|
|
</p>
|
|
|
|
{/* Current Progress */}
|
|
<div className="mb-6">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h4 className="text-[16px] font-medium text-foreground">Current Progress</h4>
|
|
<span className="text-[14px] font-medium text-muted-foreground">Week 5</span>
|
|
</div>
|
|
|
|
<div className="mb-4">
|
|
<p className="text-[14px] text-muted-foreground mb-2">Your next milestone</p>
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-4 h-4 rounded-full border-2 border-[var(--color-brand-primary)] flex items-center justify-center">
|
|
<div className="w-2 h-2 bg-[var(--color-brand-primary)] rounded-full" />
|
|
</div>
|
|
<div>
|
|
<p className="text-[14px] font-medium text-foreground">Team Building Course</p>
|
|
<p className="text-[12px] text-muted-foreground">Due in 5 days</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Program Timeline */}
|
|
<div>
|
|
<h4 className="text-[16px] font-medium text-foreground mb-4">Program timeline</h4>
|
|
|
|
<div className="space-y-4">
|
|
{/* Start date */}
|
|
<div className="flex items-start gap-3">
|
|
<div className="w-5 h-5 rounded-full bg-[#21A36A] flex items-center justify-center flex-shrink-0 mt-0.5">
|
|
<Check className="h-3 w-3 text-white" />
|
|
</div>
|
|
<div>
|
|
<p className="text-[14px] font-medium text-foreground">Start date: January 15, 2024</p>
|
|
<p className="text-[12px] text-muted-foreground">Program commenced</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Current course */}
|
|
<div className="flex items-start gap-3">
|
|
<div className="w-5 h-5 rounded-full bg-[var(--color-brand-primary)] flex items-center justify-center flex-shrink-0 mt-0.5">
|
|
<span className="text-[12px] font-medium text-white">3</span>
|
|
</div>
|
|
<div>
|
|
<p className="text-[14px] font-medium text-foreground">Building High-Performance Teams</p>
|
|
<p className="text-[12px] text-muted-foreground">In progress - Due March 15</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* End date */}
|
|
<div className="flex items-start gap-3">
|
|
<div className="w-5 h-5 flex items-center justify-center flex-shrink-0 mt-0.5">
|
|
<Award className="h-4 w-4 text-muted-foreground" />
|
|
</div>
|
|
<div>
|
|
<p className="text-[14px] font-medium text-foreground">Expected completion: April 15, 2024</p>
|
|
<p className="text-[12px] text-muted-foreground">Program certificate</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |