'use client'; import { useState, useEffect } from 'react'; import { useTranslations } from 'next-intl'; import { createLesson, updateLesson, getLessons, deleteLesson, getDashboardStats } from '@/lib/actions/lessonActions'; import { getUsers, createAdminUser } from '@/lib/actions/userActions'; import { getSettings, updateSettings } from '@/lib/actions/settingsActions'; import { getContactMessages } from '@/lib/actions/contactActions'; import { getCategories, createCategory, updateCategory, deleteCategory } from '@/lib/actions/categoryActions'; import { getCheatsheets, createCheatsheet, updateCheatsheet, deleteCheatsheet } from '@/lib/actions/cheatsheetActions'; import { getPrompts, createPrompt, updatePrompt, deletePrompt } from '@/lib/actions/promptActions'; import { ShieldAlert, Plus, Save, FileCode, CheckCircle2, Trash2, Edit, LayoutDashboard, BookOpen, Users, Settings as SettingsIcon, MessageSquare, Eye, Download, Video, Loader2, Search, X, Clock, FileText, Link as LinkIcon, FolderTree, Tag, Terminal, Sparkles } from 'lucide-react'; import { YoutubeIcon as Youtube } from '@/components/icons/YoutubeIcon'; function parseChaptersText(text: string) { if (!text || !text.trim()) return []; const lines = text.split('\n'); const result: { time: string; seconds: number; title: string }[] = []; for (const line of lines) { const trimmed = line.trim(); if (!trimmed) continue; const match = trimmed.match(/^(\d{1,2}:\d{2}(?::\d{2})?)\s*[-:]?\s*(.+)$/); if (match) { const timeStr = match[1]; const titleStr = match[2]; const parts = timeStr.split(':').map(Number); let seconds = 0; if (parts.length === 2) { seconds = parts[0] * 60 + parts[1]; } else if (parts.length === 3) { seconds = parts[0] * 3600 + parts[1] * 60 + parts[2]; } result.push({ time: timeStr, seconds, title: titleStr }); } } return result; } function parseNotesText(text: string) { if (!text || !text.trim()) return []; return text .split('\n') .map((l) => l.trim()) .filter((l) => l.length > 0); } export default function AdminPage() { const t = useTranslations('admin'); const [activeTab, setActiveTab] = useState<'dashboard' | 'lessons' | 'cheatsheets' | 'prompts' | 'categories' | 'users' | 'settings' | 'messages'>('dashboard'); // Stats const [stats, setStats] = useState({ totalLessons: 0, totalViews: 0, totalDownloads: 0, totalMessages: 0 }); // Lessons list & Search const [lessons, setLessons] = useState([]); const [lessonSearch, setLessonSearch] = useState(''); const [loadingLessons, setLoadingLessons] = useState(false); // Dynamic Categories State const [categoriesList, setCategoriesList] = useState([]); const [newCatName, setNewCatName] = useState(''); const [editingCatId, setEditingCatId] = useState(null); const [editingCatName, setEditingCatName] = useState(''); // Cheatsheets State const [cheatsheetsList, setCheatsheetsList] = useState([]); const [isCheatFormOpen, setIsCheatFormOpen] = useState(false); const [editingCheatId, setEditingCheatId] = useState(null); const [cheatTitle, setCheatTitle] = useState(''); const [cheatCategory, setCheatCategory] = useState('Git'); const [cheatDesc, setCheatDesc] = useState(''); const [cheatItems, setCheatItems] = useState<{ command: string; description: string }[]>([ { command: 'git status', description: 'Check working tree status' }, ]); const [savingCheat, setSavingCheat] = useState(false); // Prompts State const [promptsList, setPromptsList] = useState([]); const [isPromptFormOpen, setIsPromptFormOpen] = useState(false); const [editingPromptId, setEditingPromptId] = useState(null); const [promptTitle, setPromptTitle] = useState(''); const [promptCategory, setPromptCategory] = useState('System Architecture'); const [promptDesc, setPromptDesc] = useState(''); const [promptContent, setPromptContent] = useState(''); const [promptTagsText, setPromptTagsText] = useState('Next.js, System Prompt'); const [promptIsOpen, setPromptIsOpen] = useState(false); const [savingPrompt, setSavingPrompt] = useState(false); // Lesson Form Modal State (Create or Edit) const [isFormOpen, setIsFormOpen] = useState(false); const [editingLessonId, setEditingLessonId] = useState(null); const [formTitle, setFormTitle] = useState(''); const [formYoutubeUrl, setFormYoutubeUrl] = useState(''); const [formCategory, setFormCategory] = useState('Next.js'); const [formDuration, setFormDuration] = useState('15:00'); const [formSummary, setFormSummary] = useState(''); const [formChaptersText, setFormChaptersText] = useState(''); const [formNotesText, setFormNotesText] = useState(''); const [formDownloads, setFormDownloads] = useState< { title: string; type: string; url: string; size?: string }[] >([]); const [formSnippets, setFormSnippets] = useState< { fileName: string; language: string; code: string }[] >([{ fileName: 'app/page.tsx', language: 'typescript', code: '' }]); const [savingLesson, setSavingLesson] = useState(false); // Users State const [usersList, setUsersList] = useState([]); const [newAdminName, setNewAdminName] = useState(''); const [newAdminEmail, setNewAdminEmail] = useState(''); const [newAdminPass, setNewAdminPass] = useState(''); const [savingUser, setSavingUser] = useState(false); // Settings State const [settings, setSettingsData] = useState>({ channelName: '', youtubeUrl: '', githubUrl: '', contactEmail: '', defaultCategory: 'Next.js', }); const [savingSettings, setSavingSettings] = useState(false); // Messages State const [messages, setMessages] = useState([]); // Alert Notifications const [alert, setAlert] = useState<{ type: 'success' | 'error'; msg: string } | null>(null); useEffect(() => { loadTabContent(); }, [activeTab]); useEffect(() => { // Pre-fetch categories for lesson modal getCategories().then((cats) => { setCategoriesList(cats); if (cats.length > 0 && !formCategory) { setFormCategory(cats[0].name); } }); }, []); async function loadTabContent() { if (activeTab === 'dashboard') { const [st, les] = await Promise.all([getDashboardStats(), getLessons()]); setStats(st); setLessons(les.slice(0, 5)); } else if (activeTab === 'lessons') { setLoadingLessons(true); const [les, cats] = await Promise.all([getLessons({ query: lessonSearch }), getCategories()]); setLessons(les); setCategoriesList(cats); setLoadingLessons(false); } else if (activeTab === 'cheatsheets') { const sheets = await getCheatsheets(); setCheatsheetsList(sheets); } else if (activeTab === 'prompts') { const prs = await getPrompts(); setPromptsList(prs); } else if (activeTab === 'categories') { const cats = await getCategories(); setCategoriesList(cats); } else if (activeTab === 'users') { const u = await getUsers(); setUsersList(u); } else if (activeTab === 'settings') { const s = await getSettings(); setSettingsData(s); } else if (activeTab === 'messages') { const m = await getContactMessages(); setMessages(m); } } // Filter lessons on search typing useEffect(() => { if (activeTab === 'lessons') { getLessons({ query: lessonSearch }).then(setLessons); } }, [lessonSearch]); const showAlert = (type: 'success' | 'error', msg: string) => { setAlert({ type, msg }); setTimeout(() => setAlert(null), 4000); }; // Open Create Form const handleOpenCreate = () => { setEditingLessonId(null); setFormTitle(''); setFormYoutubeUrl(''); setFormCategory(categoriesList[0]?.name || 'Next.js'); setFormDuration('15:00'); setFormSummary(''); setFormChaptersText(''); setFormNotesText(''); setFormDownloads([]); setFormSnippets([{ fileName: 'app/page.tsx', language: 'typescript', code: '' }]); setIsFormOpen(true); }; // Open Edit Form const handleOpenEdit = (lesson: any) => { setEditingLessonId(lesson.id); setFormTitle(lesson.title); setFormYoutubeUrl(lesson.youtubeUrl); setFormCategory(lesson.category); setFormDuration(lesson.duration || '15:00'); setFormSummary(lesson.summary); setFormNotesText(lesson.notesMarkdown ? lesson.notesMarkdown.join('\n') : ''); setFormChaptersText( lesson.chapters ? lesson.chapters.map((c: any) => `${c.time} - ${c.title}`).join('\n') : '' ); setFormDownloads( lesson.downloads ? lesson.downloads.map((d: any) => ({ title: d.title, type: d.type, url: d.url, size: d.size || '1.0 MB', })) : [] ); if (lesson.codeSnippets && lesson.codeSnippets.length > 0) { setFormSnippets( lesson.codeSnippets.map((s: any) => ({ fileName: s.fileName, language: s.language, code: s.code, })) ); } else { setFormSnippets([{ fileName: 'app/page.tsx', language: 'typescript', code: '' }]); } setIsFormOpen(true); }; const handleAddSnippet = () => { setFormSnippets([...formSnippets, { fileName: 'app/actions.ts', language: 'typescript', code: '' }]); }; const handleRemoveSnippet = (idx: number) => { setFormSnippets(formSnippets.filter((_, i) => i !== idx)); }; const handleAddDownload = () => { setFormDownloads([ ...formDownloads, { title: 'Completed Project (.zip)', type: 'zip', url: '#', size: '2.5 MB' }, ]); }; const handleRemoveDownload = (idx: number) => { setFormDownloads(formDownloads.filter((_, i) => i !== idx)); }; // Save (Create or Update) Lesson const handleSaveLesson = async (e: React.FormEvent) => { e.preventDefault(); setSavingLesson(true); const chapters = parseChaptersText(formChaptersText); const notesMarkdown = parseNotesText(formNotesText); let res; if (editingLessonId) { res = await updateLesson(editingLessonId, { title: formTitle, youtubeUrl: formYoutubeUrl, category: formCategory, duration: formDuration, summary: formSummary, chapters, notesMarkdown, downloads: formDownloads, codeSnippets: formSnippets, }); } else { res = await createLesson({ title: formTitle, youtubeUrl: formYoutubeUrl, category: formCategory, duration: formDuration, summary: formSummary, chapters, notesMarkdown, downloads: formDownloads, codeSnippets: formSnippets, }); } setSavingLesson(false); if (res.success) { showAlert('success', editingLessonId ? 'Lesson updated successfully!' : 'New lesson created successfully!'); setIsFormOpen(false); loadTabContent(); } else { showAlert('error', res.error || 'Failed to save lesson'); } }; // Prompt Handlers const handleOpenPromptCreate = () => { setEditingPromptId(null); setPromptTitle(''); setPromptCategory('System Architecture'); setPromptDesc(''); setPromptContent(''); setPromptTagsText('Next.js, System Prompt'); setIsPromptFormOpen(true); }; const handleOpenPromptEdit = (prompt: any) => { setEditingPromptId(prompt.id); setPromptTitle(prompt.title); setPromptCategory(prompt.category); setPromptDesc(prompt.description); setPromptContent(prompt.content); setPromptTagsText(prompt.tags ? prompt.tags.join(', ') : ''); setIsPromptFormOpen(true); }; const handleSavePrompt = async (e: React.FormEvent) => { e.preventDefault(); setSavingPrompt(true); const tags = promptTagsText.split(',').map((t) => t.trim()).filter((t) => t.length > 0); let res; if (editingPromptId) { res = await updatePrompt(editingPromptId, { title: promptTitle, category: promptCategory, description: promptDesc, content: promptContent, tags, isOpen: promptIsOpen, }); } else { res = await createPrompt({ title: promptTitle, category: promptCategory, description: promptDesc, content: promptContent, tags, isOpen: promptIsOpen, }); } setSavingPrompt(false); if (res.success) { showAlert('success', editingPromptId ? 'Prompt updated successfully!' : 'New prompt created successfully!'); setIsPromptFormOpen(false); getPrompts().then(setPromptsList); } else { showAlert('error', res.error || 'Failed to save prompt'); } }; const handleDeletePrompt = async (id: string, title: string) => { if (!confirm(`Are you sure you want to delete prompt "${title}"?`)) return; const res = await deletePrompt(id); if (res.success) { showAlert('success', `Prompt "${title}" deleted`); getPrompts().then(setPromptsList); } else { showAlert('error', res.error || 'Failed to delete prompt'); } }; // Cheatsheet Handlers const handleOpenCheatCreate = () => { setEditingCheatId(null); setCheatTitle(''); setCheatCategory('Git'); setCheatDesc(''); setCheatItems([{ command: 'git status', description: 'Check working tree status' }]); setIsCheatFormOpen(true); }; const handleOpenCheatEdit = (sheet: any) => { setEditingCheatId(sheet.id); setCheatTitle(sheet.title); setCheatCategory(sheet.category); setCheatDesc(sheet.description); setCheatItems( sheet.items && sheet.items.length > 0 ? sheet.items.map((i: any) => ({ command: i.command, description: i.description })) : [{ command: '', description: '' }] ); setIsCheatFormOpen(true); }; const handleSaveCheatsheet = async (e: React.FormEvent) => { e.preventDefault(); setSavingCheat(true); let res; if (editingCheatId) { res = await updateCheatsheet(editingCheatId, { title: cheatTitle, category: cheatCategory, description: cheatDesc, items: cheatItems, }); } else { res = await createCheatsheet({ title: cheatTitle, category: cheatCategory, description: cheatDesc, items: cheatItems, }); } setSavingCheat(false); if (res.success) { showAlert('success', editingCheatId ? 'Cheatsheet updated successfully!' : 'New cheatsheet created successfully!'); setIsCheatFormOpen(false); getCheatsheets().then(setCheatsheetsList); } else { showAlert('error', res.error || 'Failed to save cheatsheet'); } }; const handleDeleteCheatsheet = async (id: string, title: string) => { if (!confirm(`Are you sure you want to delete cheatsheet "${title}"?`)) return; const res = await deleteCheatsheet(id); if (res.success) { showAlert('success', `Cheatsheet "${title}" deleted`); getCheatsheets().then(setCheatsheetsList); } else { showAlert('error', res.error || 'Failed to delete cheatsheet'); } }; // Category CRUD Handlers const handleCreateCategory = async (e: React.FormEvent) => { e.preventDefault(); if (!newCatName.trim()) return; const res = await createCategory(newCatName); if (res.success) { showAlert('success', `Category "${newCatName}" created successfully!`); setNewCatName(''); getCategories().then(setCategoriesList); } else { showAlert('error', res.error || 'Failed to create category'); } }; const handleUpdateCategory = async (id: string) => { if (!editingCatName.trim()) return; const res = await updateCategory(id, editingCatName); if (res.success) { showAlert('success', 'Category updated successfully!'); setEditingCatId(null); setEditingCatName(''); getCategories().then(setCategoriesList); } else { showAlert('error', res.error || 'Failed to update category'); } }; const handleDeleteCategory = async (id: string, name: string) => { if (!confirm(`Are you sure you want to delete category "${name}"?`)) return; const res = await deleteCategory(id); if (res.success) { showAlert('success', `Category "${name}" deleted`); getCategories().then(setCategoriesList); } else { showAlert('error', res.error || 'Failed to delete category'); } }; // Delete Lesson const handleDeleteLesson = async (id: string) => { if (!confirm('Are you sure you want to delete this tutorial?')) return; const res = await deleteLesson(id); if (res.success) { showAlert('success', 'Lesson deleted'); setLessons(lessons.filter((l) => l.id !== id)); } }; // Create Admin User const handleCreateUser = async (e: React.FormEvent) => { e.preventDefault(); setSavingUser(true); const res = await createAdminUser({ name: newAdminName, email: newAdminEmail, password: newAdminPass }); setSavingUser(false); if (res.success) { showAlert('success', 'New Admin user created successfully!'); setNewAdminName(''); setNewAdminEmail(''); setNewAdminPass(''); getUsers().then(setUsersList); } else { showAlert('error', res.error || 'Failed to create user'); } }; // Save Settings const handleSaveSettings = async (e: React.FormEvent) => { e.preventDefault(); setSavingSettings(true); const res = await updateSettings(settings); setSavingSettings(false); if (res.success) { showAlert('success', 'Settings updated successfully!'); } else { showAlert('error', res.error || 'Failed to update settings'); } }; return (
{/* Left Vertical Sidebar Navigation */} {/* Main Content View */}
{/* Alert Banner */} {alert && (
{alert.msg}
)} {/* TAB 1: DASHBOARD STATS */} {activeTab === 'dashboard' && (
{/* Stat Cards Grid */}
Total Tutorials
{stats.totalLessons}
Total Views
{stats.totalViews.toLocaleString()}
Project Downloads
{stats.totalDownloads.toLocaleString()}
Viewer Inquiries
{stats.totalMessages}
{/* Recent Lessons Table Preview */}

Recent YouTube Tutorials

{lessons.map((lesson) => (
{lesson.category}

{lesson.title}

))}
)} {/* TAB 2: LESSONS & EDIT MODAL */} {activeTab === 'lessons' && (
{/* Search Input */}
setLessonSearch(e.target.value)} className="w-full bg-slate-900 border border-slate-800 rounded-xl pl-10 pr-4 py-2 text-xs text-white placeholder-slate-500 focus:outline-none" />
{/* Lessons Table / List */} {loadingLessons ? (
Loading tutorials...
) : lessons.length > 0 ? (
{lessons.map((item) => (
{item.category} {item.codeSnippets?.length || 0} Files | {item.chapters?.length || 0} Timestamps

{item.title}

{item.summary}

))}
) : (
No tutorials found.
)}
)} {/* TAB 3: CHEATSHEETS CRUD */} {activeTab === 'cheatsheets' && (

Cheatsheets & Commands ({cheatsheetsList.length})

{cheatsheetsList.map((sheet) => (
{sheet.category}

{sheet.title}

{sheet.description}

{sheet.items?.slice(0, 3).map((item: any, idx: number) => (
{item.command} {item.description}
))}
))}
)} {/* TAB 4: PROMPTS CRUD */} {activeTab === 'prompts' && (

AI Prompts & Templates ({promptsList.length})

{promptsList.map((prompt) => (
{prompt.category}

{prompt.title}

{prompt.description}

{prompt.content}
))}
)} {/* TAB 5: CATEGORIES CRUD */} {activeTab === 'categories' && (
{/* Create Category Form */}

Create New Category

setNewCatName(e.target.value)} className="bg-slate-950 border border-slate-800 rounded-xl px-4 py-2.5 text-xs text-white focus:outline-none flex-1" />
{/* Categories List */}

Categories ({categoriesList.length})

{categoriesList.map((cat) => (
{editingCatId === cat.id ? (
setEditingCatName(e.target.value)} className="bg-slate-900 border border-slate-700 rounded-lg px-3 py-1 text-xs text-white focus:outline-none flex-1" />
) : ( <>
{cat.name}
)}
))}
)} {/* TAB 6: USERS / ADMINS */} {activeTab === 'users' && (
{/* Create User Form */}

Add New Admin User

setNewAdminName(e.target.value)} className="bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-xs text-white focus:outline-none" /> setNewAdminEmail(e.target.value)} className="bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-xs text-white focus:outline-none" /> setNewAdminPass(e.target.value)} className="bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-xs text-white focus:outline-none" />
{/* Users List Table */}

Admin Users ({usersList.length})

{usersList.map((u) => (
{u.name || 'Admin User'} {u.email}
{u.role}
))}
)} {/* TAB 7: SETTINGS */} {activeTab === 'settings' && (

Channel & Creator Settings

setSettingsData({ ...settings, channelName: e.target.value })} className="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2.5 text-xs text-white focus:outline-none" />
setSettingsData({ ...settings, youtubeUrl: e.target.value })} className="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2.5 text-xs text-white focus:outline-none" />
setSettingsData({ ...settings, githubUrl: e.target.value })} className="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2.5 text-xs text-white focus:outline-none" />
setSettingsData({ ...settings, contactEmail: e.target.value })} className="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2.5 text-xs text-white focus:outline-none" />
)} {/* TAB 8: MESSAGES */} {activeTab === 'messages' && (

Viewer Contact Messages ({messages.length})

{messages.length > 0 ? (
{messages.map((msg) => (
{msg.name} ({msg.email}) {new Date(msg.createdAt).toLocaleString()}

{msg.subject}

{msg.message}

))}
) : (
No viewer contact messages received yet.
)}
)}
{/* CREATE / EDIT PROMPT FORM MODAL */} {isPromptFormOpen && (

{editingPromptId ? 'Edit AI Prompt' : 'Create New AI Prompt'}

setPromptTitle(e.target.value)} placeholder="Full-Stack Next.js Architect" className="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-xs text-white focus:outline-none" />
setPromptCategory(e.target.value)} placeholder="System Architecture / UI Design" className="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-2 text-xs text-white focus:outline-none" />