Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9,638 changes: 2,357 additions & 7,281 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

26 changes: 7 additions & 19 deletions src/app/api/courses/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ import {

export const runtime = 'edge';

// ---------------------------------------------------------------------------
// GET /api/courses/[id]
// ---------------------------------------------------------------------------

export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> },
Expand Down Expand Up @@ -53,21 +49,13 @@ export async function GET(
return withSecurityHeaders(addHeaders(result.error)) as NextResponse<CourseResponseDTO>;
}

// Mock course lookup — replace with real DB query
const course = {
id: result.data.id,
title: 'Web3 UX Design Principles',
description: 'Create intuitive interfaces for decentralized applications',
instructor: 'Sarah Johnson',
duration: '24 hours',
totalLessons: 12,
progress: 68,
category: 'Design',
size: '250MB',
thumbnailUrl:
'https://thumbs.dreamstime.com/b/matrix-style-digital-rain-green-binary-code-falling-downward-direction-abstract-background-depicting-effect-stream-397887374.jpg',
downloaded: false,
};
const course = getCourseById(result.data.id);
if (!course) {
const notFound = addHeaders(
NextResponse.json({ data: null as unknown as CourseResponseDTO['data'], success: false, message: 'Course not found' }, { status: 404 }),
);
return notFound as NextResponse<CourseResponseDTO>;
}

const sanitizedCourse = sanitizeObject(course);

Expand Down
40 changes: 12 additions & 28 deletions src/app/api/courses/downloadable/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,18 @@ export async function GET(request: Request) {
return withSecurityHeaders(rateLimitResponse);
}

const courses = [
{
id: '1',
title: 'Web3 UX Design Principles',
description: 'Create intuitive interfaces for decentralized applications',
instructor: 'Sarah Johnson',
duration: '24 hours',
totalLessons: 12,
progress: 68,
size: '250MB',
thumbnailUrl:
'https://thumbs.dreamstime.com/b/matrix-style-digital-rain-green-binary-code-falling-downward-direction-abstract-background-depicting-effect-stream-397887374.jpg',
downloaded: false,
},
{
id: '2',
title: 'Smart Contract Security Best Practices',
description: 'Learn to secure your Cairo smart contracts against vulnerabilities',
instructor: 'Michael Chen',
duration: '36 hours',
totalLessons: 18,
progress: 45,
size: '380MB',
thumbnailUrl:
'https://static.vecteezy.com/system/resources/previews/053/715/379/non_2x/abstract-green-digital-rain-with-matrix-code-in-futuristic-cyber-background-perfect-for-technology-and-data-themed-visuals-png.png',
downloaded: false,
},
];
const courses = getAllCourses().map(({ id, title, description, instructor, duration, totalLessons, progress, size, thumbnailUrl }) => ({
id,
title,
description,
instructor,
duration,
totalLessons,
progress,
size,
thumbnailUrl,
downloaded: false,
}));

const sanitizedCourses = sanitizeObject(courses);

Expand Down
50 changes: 1 addition & 49 deletions src/app/api/courses/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,55 +38,7 @@ export async function GET(request: Request): Promise<NextResponse<CourseListResp
return withSecurityHeaders(addHeaders(result.error)) as NextResponse<CourseListResponseDTO>;
const { limit, cursor } = result.data as { limit: number; cursor?: string };

const courses = [
{
id: '1',
title: 'Web3 UX Design Principles',
description: 'Create intuitive interfaces for decentralized applications',
instructor: 'Sarah Johnson',
duration: '24 hours',
totalLessons: 12,
progress: 68,
category: 'Design',
size: '250MB',
thumbnailUrl:
'https://thumbs.dreamstime.com/b/matrix-style-digital-rain-green-binary-code-falling-downward-direction-abstract-background-depicting-effect-stream-397887374.jpg',
downloaded: false,
},
{
id: '2',
title: 'Smart Contract Security Best Practices',
description: 'Learn to secure your Cairo smart contracts against vulnerabilities',
instructor: 'Michael Chen',
duration: '36 hours',
totalLessons: 18,
progress: 45,
category: 'Security',
size: '380MB',
thumbnailUrl:
'https://static.vecteezy.com/system/resources/previews/053/715/379/non_2x/abstract-green-digital-rain-with-matrix-code-in-futuristic-cyber-background-perfect-for-technology-and-data-themed-visuals-png.png',
downloaded: true,
},
{
id: '3',
title: 'Scaling DAPps on Starknet',
description: 'Techniques for building scalable decentralized applications',
instructor: 'Alex Rivera',
duration: '48 hours',
totalLessons: 24,
progress: 12,
category: 'Engineering',
size: '520MB',
thumbnailUrl:
'https://thumbs.dreamstime.com/b/futuristic-laptop-glowing-digital-waves-emerging-screen-dark-setting-399809314.jpg',
downloaded: false,
},
];

const startIndex = cursor ? parseInt(cursor, 10) : 0;
const page = courses.slice(startIndex, startIndex + limit);
const nextIndex = startIndex + limit;
const nextCursor = nextIndex < courses.length ? String(nextIndex) : undefined;
const paginated = getPaginatedCourses(limit, cursor, { featured });

const sanitizedPage = sanitizeObject(page);

Expand Down
96 changes: 58 additions & 38 deletions src/app/components/dashboard/widgets/RecommendedCoursesWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react';
import { AccessibleLoading } from '../../accessibility/ScreenReaderOptimizer';
import { motion } from 'framer-motion';
import { BookOpen, Star, Clock, Users, Settings } from 'lucide-react';
import { getAllCourses } from '@/lib/course-config';

interface Course {
id: string;
Expand Down Expand Up @@ -29,6 +30,62 @@ interface RecommendedCoursesWidgetProps {
onUpdateTitle: (title: string) => void;
}

function buildRecommendedCourses() {
const configCourses = getAllCourses();
if (configCourses.length >= 3) {
return configCourses.slice(0, 3).map((c, i) => ({
id: c.id,
title: c.title,
instructor: c.instructor,
rating: (4.5 + i * 0.2) as 4.7 | 4.8 | 4.9,
students: [12450, 8920, 15680][i] ?? 10000,
duration: c.duration,
level: (i === 2 ? 'beginner' : i === 1 ? 'intermediate' : 'advanced') as 'beginner' | 'intermediate' | 'advanced',
category: c.category,
image: c.thumbnailUrl ?? `https://via.placeholder.com/300x200/${['3B82F6', '10B981', '8B5CF6'][i]}/ffffff?text=${encodeURIComponent(c.title.split(' ')[0])}`,
price: [89, 129, 69][i] ?? 99,
}));
}
return [
{
id: '1',
title: 'Advanced React Patterns',
instructor: 'Sarah Johnson',
rating: 4.8 as const,
students: 12450,
duration: '8 hours',
level: 'advanced' as const,
category: 'Web Development',
image: 'https://via.placeholder.com/300x200/3B82F6/ffffff?text=React',
price: 89,
},
{
id: '2',
title: 'Machine Learning Fundamentals',
instructor: 'Dr. Michael Chen',
rating: 4.9 as const,
students: 8920,
duration: '12 hours',
level: 'intermediate' as const,
category: 'Data Science',
image: 'https://via.placeholder.com/300x200/10B981/ffffff?text=ML',
price: 129,
},
{
id: '3',
title: 'UI/UX Design Principles',
instructor: 'Emma Davis',
rating: 4.7 as const,
students: 15680,
duration: '6 hours',
level: 'beginner' as const,
category: 'Design',
image: 'https://via.placeholder.com/300x200/8B5CF6/ffffff?text=Design',
price: 69,
},
];
}

export const RecommendedCoursesWidget: React.FC<RecommendedCoursesWidgetProps> = ({
id,
title,
Expand Down Expand Up @@ -69,44 +126,7 @@ export const RecommendedCoursesWidget: React.FC<RecommendedCoursesWidgetProps> =
};
}, [id]);

const recommendedCourses: Course[] = [
{
id: '1',
title: 'Advanced React Patterns',
instructor: 'Sarah Johnson',
rating: 4.8,
students: 12450,
duration: '8 hours',
level: 'advanced',
category: 'Web Development',
image: 'https://via.placeholder.com/300x200/3B82F6/ffffff?text=React',
price: 89,
},
{
id: '2',
title: 'Machine Learning Fundamentals',
instructor: 'Dr. Michael Chen',
rating: 4.9,
students: 8920,
duration: '12 hours',
level: 'intermediate',
category: 'Data Science',
image: 'https://via.placeholder.com/300x200/10B981/ffffff?text=ML',
price: 129,
},
{
id: '3',
title: 'UI/UX Design Principles',
instructor: 'Emma Davis',
rating: 4.7,
students: 15680,
duration: '6 hours',
level: 'beginner',
category: 'Design',
image: 'https://via.placeholder.com/300x200/8B5CF6/ffffff?text=Design',
price: 69,
},
];
const recommendedCourses = buildRecommendedCourses();

const getLevelColor = (level: string) => {
switch (level) {
Expand Down
54 changes: 53 additions & 1 deletion src/app/components/home/HomeContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,62 @@
import Link from 'next/link';
import { useInternationalization } from '@/hooks/useInternationalization';
import CourseCard from '../courses/CourseCard';
import type { CourseEntry } from '@/lib/course-config/types';

export default function HomeContent() {
interface FeaturedCourseData {
title: string;
subtitle: string;
author: string;
progress: number;
timeRemaining: string;
imageUrl?: string;
courseHref: string;
}

interface HomeContentProps {
featuredCourses?: FeaturedCourseData[];
}

function fallbackFeaturedCourses(): FeaturedCourseData[] {
return [
{
title: 'Web3 UX Design Principles',
subtitle: 'Create intuitive interfaces for decentralized applications',
author: 'Sarah Johnson',
progress: 68,
timeRemaining: '12h remaining',
imageUrl:
'https://thumbs.dreamstime.com/b/matrix-style-digital-rain-green-binary-code-falling-downward-direction-abstract-background-depicting-effect-stream-397887374.jpg',
courseHref: '/courses/1',
},
{
title: 'Smart Contract Security Best Practices',
subtitle: 'Learn to secure your Cairo smart contracts against vulnerabilities',
author: 'Michael Chen',
progress: 45,
timeRemaining: '12h remaining',
imageUrl:
'https://static.vecteezy.com/system/resources/previews/053/715/379/non_2x/abstract-green-digital-rain-with-matrix-code-in-futuristic-cyber-background-perfect-for-technology-and-data-themed-visuals-png.png',
courseHref: '/courses/2',
},
{
title: 'Scaling DAPps on Starknet',
subtitle: 'Techniques for building scalable decentralized applications',
author: 'Alex Rivera',
progress: 12,
timeRemaining: '12h remaining',
imageUrl:
'https://thumbs.dreamstime.com/b/futuristic-laptop-glowing-digital-waves-emerging-screen-dark-setting-399809314.jpg',
courseHref: '/courses/3',
},
];
}

export default function HomeContent({ featuredCourses }: HomeContentProps) {
const { t, language, changeLanguage, isLoading } = useInternationalization();

const courses = featuredCourses ?? fallbackFeaturedCourses();

return (
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 text-white">
<header className="px-4 py-6 md:px-8">
Expand Down
14 changes: 13 additions & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Metadata } from 'next';
import HomeContent from './components/home/HomeContent';
import { getFeaturedCourses } from '@/lib/course-config';

export const metadata: Metadata = {
title: 'TeachLink - Offline Learning Platform',
Expand All @@ -18,5 +19,16 @@ export const metadata: Metadata = {
};

export default function Home() {
return <HomeContent />;
const featured = getFeaturedCourses(3);
const featuredCourses = featured.map((course) => ({
title: course.title,
subtitle: course.subtitle ?? course.description,
author: course.author ?? course.instructor,
progress: course.progress,
timeRemaining: course.timeRemaining ?? '12h remaining',
imageUrl: course.thumbnailUrl,
courseHref: `/courses/${course.id}`,
}));

return <HomeContent featuredCourses={featuredCourses} />;
}
Loading
Loading