Files
pwap/web/src/pages/EducationPlatform.tsx
T
pezkuwichain a635610b7c feat: Phase 1B complete - Perwerde & ValidatorPool UI
Perwerde (Education Platform):
- Add hybrid backend (Supabase + Blockchain + IPFS)
- Implement CourseList, CourseCreator, StudentDashboard
- Create courses table with RLS policies
- Add IPFS upload utility
- Integrate with pallet-perwerde extrinsics

ValidatorPool:
- Add validator pool management UI
- Implement PoolCategorySelector with 3 categories
- Add ValidatorPoolDashboard with pool stats
- Integrate with pallet-validator-pool extrinsics
- Add to StakingDashboard as new tab

Technical:
- Fix all toast imports (sonner)
- Fix IPFS File upload (Blob conversion)
- Fix RLS policies (wallet_address → auth.uid)
- Add error boundaries
- Add loading states

Status: UI complete, blockchain integration pending VPS deployment
2025-11-17 05:04:51 +03:00

108 lines
3.7 KiB
TypeScript

import React, { useState, useEffect, useCallback } from 'react';
import { GraduationCap } from 'lucide-react';
import { useAuth } from '@/contexts/AuthContext';
import { usePolkadot } from '@/contexts/PolkadotContext';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { CourseList } from '@/components/perwerde/CourseList';
import { StudentDashboard } from '@/components/perwerde/StudentDashboard';
import { CourseCreator } from '@/components/perwerde/CourseCreator';
import { getStudentEnrollments, type Enrollment } from '@shared/lib/perwerde';
import { toast } from 'sonner';
import { AsyncComponent, LoadingState } from '@shared/components/AsyncComponent';
import { useNavigate } from 'react-router-dom';
import { Button } from '@/components/ui/button';
export default function EducationPlatform() {
const { user } = useAuth();
const { selectedAccount } = usePolkadot();
const [enrollments, setEnrollments] = useState<Enrollment[]>([]);
const [loading, setLoading] = useState(true);
const [activeTab, setActiveTab] = useState('courses');
const navigate = useNavigate();
const isAdmin = user?.role === 'admin';
const fetchEnrollments = useCallback(async () => {
if (!selectedAccount) {
setEnrollments([]);
return;
}
try {
setLoading(true);
const studentEnrollments = await getStudentEnrollments(selectedAccount.address);
setEnrollments(studentEnrollments);
} catch (error) {
console.error('Failed to fetch enrollments:', error);
toast({
title: 'Error',
description: 'Failed to fetch your enrollments.',
variant: 'destructive',
});
} finally {
setLoading(false);
}
}, [selectedAccount]);
useEffect(() => {
fetchEnrollments();
}, [fetchEnrollments]);
const handleDataChange = () => {
// Refetch enrollments after an action
fetchEnrollments();
};
return (
<div className="container mx-auto px-4 py-8 max-w-7xl">
<div className="mb-8 flex items-center justify-between">
<div>
<h1 className="text-4xl font-bold text-white mb-2 flex items-center gap-3">
<GraduationCap className="w-10 h-10 text-green-500" />
Perwerde - Education Platform
</h1>
<p className="text-gray-400">
Decentralized learning for Digital Kurdistan. Build skills, earn credentials, empower our nation.
</p>
</div>
<Button onClick={() => navigate('/')} className="bg-gray-700 hover:bg-gray-600 text-white">
Back to Home
</Button>
</div>
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-4">
<TabsList>
<TabsTrigger value="courses">Available Courses</TabsTrigger>
{selectedAccount && <TabsTrigger value="dashboard">My Dashboard</TabsTrigger>}
{isAdmin && <TabsTrigger value="create">Create Course</TabsTrigger>}
</TabsList>
<TabsContent value="courses">
<CourseList
enrolledCourseIds={enrollments.map(e => e.course_id)}
onEnroll={handleDataChange}
/>
</TabsContent>
{selectedAccount && (
<TabsContent value="dashboard">
<StudentDashboard
enrollments={enrollments}
loading={loading}
onCourseCompleted={handleDataChange}
/>
</TabsContent>
)}
{isAdmin && (
<TabsContent value="create">
<CourseCreator onCourseCreated={() => {
handleDataChange();
setActiveTab('courses'); // Switch back to course list after creation
}} />
</TabsContent>
)}
</Tabs>
</div>
);
}