Import source: app/src/components/LmsPanel
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,72 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
export function LmsPanel() {
|
||||||
|
const [paths, setPaths] = useState([]);
|
||||||
|
const [certificates, setCertificates] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchData() {
|
||||||
|
try {
|
||||||
|
const [pathsRes, certsRes] = await Promise.all([
|
||||||
|
fetch('/api/lms/paths').then(r => r.json()),
|
||||||
|
fetch('/api/lms/me').then(r => r.json()).catch(() => ({ certificates: [] }))
|
||||||
|
]);
|
||||||
|
if (pathsRes.paths) setPaths(pathsRes.paths);
|
||||||
|
if (certsRes.certificates) setCertificates(certsRes.certificates);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) return <div className="p-8 text-center text-brand-muted">در حال بارگذاری دورهها...</div>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="lms-panel" style={{ padding: '2rem', maxWidth: '1000px', margin: '0 auto', direction: 'rtl' }}>
|
||||||
|
<h1 className="text-3xl font-bold mb-6 text-brand">دورههای آموزشی و مسیرهای یادگیری</h1>
|
||||||
|
|
||||||
|
{certificates.length > 0 && (
|
||||||
|
<div className="mb-8 p-6 bg-green-900/20 border border-green-500/30 rounded-xl">
|
||||||
|
<h2 className="text-xl font-bold mb-4 text-green-400">گواهینامههای شما</h2>
|
||||||
|
<div className="grid gap-4 md:grid-cols-2">
|
||||||
|
{certificates.map(cert => (
|
||||||
|
<div key={cert.id} className="p-4 bg-bg-surface rounded-lg border border-border">
|
||||||
|
<div className="font-bold">{cert.path.title}</div>
|
||||||
|
<div className="text-sm text-brand-muted mt-2">تاریخ صدور: {new Date(cert.issuedAt).toLocaleDateString('fa-IR')}</div>
|
||||||
|
<a href={cert.certificateUrl} className="text-brand text-sm mt-3 inline-block">مشاهده گواهینامه ←</a>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<h2 className="text-2xl font-bold mb-6">مسیرهای یادگیری</h2>
|
||||||
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
|
{paths.map(path => (
|
||||||
|
<div key={path.id} className="p-6 bg-bg-surface border border-border rounded-xl shadow-sm hover:shadow-md transition-shadow">
|
||||||
|
<h3 className="text-xl font-bold mb-2">{path.title}</h3>
|
||||||
|
<p className="text-brand-muted mb-4 text-sm">{path.description}</p>
|
||||||
|
|
||||||
|
<div className="text-sm font-bold mb-2">سرفصلها:</div>
|
||||||
|
<ul className="space-y-2 mb-4">
|
||||||
|
{path.modules.map(mod => (
|
||||||
|
<li key={mod.id} className="flex items-center gap-2 text-sm">
|
||||||
|
<span className="w-6 h-6 rounded-full bg-brand/10 text-brand flex items-center justify-center text-xs">{mod.order}</span>
|
||||||
|
<a href={`/article/${mod.article.slug}`} className="hover:text-brand transition-colors">{mod.article.title}</a>
|
||||||
|
<span className="text-xs text-brand-muted">({mod.article.readTime} دقیقه)</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<button className="w-full py-2 bg-brand text-white rounded-lg hover:bg-brand-hover transition-colors font-medium">
|
||||||
|
شروع یادگیری
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user