"use client"; import { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { Save, Eye, Plus, Edit, Trash2, Upload, Bold, Italic, List, Link as LinkIcon, Image as ImageIcon, Code, Quote, ArrowLeft, ChevronDown, ChevronRight, Palette, Smile, FileText, Settings, Database, BarChart3, TrendingUp } from 'lucide-react'; import Link from 'next/link'; import ReactMarkdown from 'react-markdown'; // API functions to replace direct Prisma usage const apiService = { async getAllProjects() { const response = await fetch('/api/projects'); if (!response.ok) throw new Error('Failed to fetch projects'); return response.json(); }, async createProject(data: any) { const response = await fetch('/api/projects', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); if (!response.ok) throw new Error('Failed to create project'); return response.json(); }, async updateProject(id: number, data: any) { const response = await fetch(`/api/projects/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); if (!response.ok) throw new Error('Failed to update project'); return response.json(); }, async deleteProject(id: number) { const response = await fetch(`/api/projects/${id}`, { method: 'DELETE' }); if (!response.ok) throw new Error('Failed to delete project'); return response.json(); } }; import AdminDashboard from '@/components/AdminDashboard'; import ImportExport from '@/components/ImportExport'; import AnalyticsDashboard from '@/components/AnalyticsDashboard'; import { useToast } from '@/components/Toast'; interface Project { id: number; title: string; description: string; content: string; tags: string[]; featured: boolean; category: string; date: string; github?: string; live?: string; published: boolean; imageUrl?: string; metaDescription?: string; keywords?: string; ogImage?: string; schema?: Record; // New 2.0 features difficulty: 'Beginner' | 'Intermediate' | 'Advanced' | 'Expert'; timeToComplete?: string; technologies: string[]; challenges: string[]; lessonsLearned: string[]; futureImprovements: string[]; demoVideo?: string; screenshots: string[]; colorScheme: string; accessibility: boolean; performance: { lighthouse: number; bundleSize: string; loadTime: string; }; analytics: { views: number; likes: number; shares: number; }; } const AdminPage = () => { const [mounted, setMounted] = useState(false); const { showProjectSaved, showProjectDeleted, showError, showWarning } = useToast(); useEffect(() => { setMounted(true); }, []); const [projects, setProjects] = useState([]); // Load projects from database on mount useEffect(() => { loadProjects(); }, []); const loadProjects = async () => { try { const result = await apiService.getAllProjects(); setProjects(result.projects); } catch (error) { console.error('Error loading projects from database:', error); } }; const [selectedProject, setSelectedProject] = useState(null); const [isPreview, setIsPreview] = useState(false); const [isProjectsCollapsed, setIsProjectsCollapsed] = useState(false); const [showTemplates, setShowTemplates] = useState(false); const [showImportExport, setShowImportExport] = useState(false); const [showAnalytics, setShowAnalytics] = useState(false); const [formData, setFormData] = useState({ title: '', description: '', content: '', tags: '', category: '', featured: false, github: '', live: '', published: true, imageUrl: '', // New 2.0 fields difficulty: 'Intermediate' as 'Beginner' | 'Intermediate' | 'Advanced' | 'Expert', timeToComplete: '', technologies: '', challenges: '', lessonsLearned: '', futureImprovements: '', demoVideo: '', screenshots: '', colorScheme: 'Dark', accessibility: true, performance: { lighthouse: 90, bundleSize: '50KB', loadTime: '1.5s' }, analytics: { views: 0, likes: 0, shares: 0 } }); const [markdownContent, setMarkdownContent] = useState(''); const categories = [ "Web Development", "Full-Stack", "Web Application", "Mobile App", "Desktop App", "API Development", "Database Design", "DevOps", "UI/UX Design", "Game Development", "Machine Learning", "Data Science", "Blockchain", "IoT", "Cybersecurity" ]; if (!mounted) { return null; } const handleSave = async () => { if (!formData.title || !formData.description || !markdownContent || !formData.category) { showWarning('Pflichtfelder fehlen', 'Bitte fΓΌlle alle erforderlichen Felder aus.'); return; } try { if (selectedProject) { // Update existing project in database const projectData = { title: formData.title, description: formData.description, content: markdownContent, tags: formData.tags ? formData.tags.split(',').map(tag => tag.trim()).filter(tag => tag) : [], category: formData.category, featured: formData.featured, github: formData.github || undefined, live: formData.live || undefined, published: formData.published, imageUrl: formData.imageUrl || undefined, difficulty: formData.difficulty, timeToComplete: formData.timeToComplete || undefined, technologies: formData.technologies ? formData.technologies.split(',').map(tech => tech.trim()).filter(tech => tech) : [], challenges: formData.challenges ? formData.challenges.split(',').map(challenge => challenge.trim()).filter(challenge => challenge) : [], lessonsLearned: formData.lessonsLearned ? formData.lessonsLearned.split(',').map(lesson => lesson.trim()).filter(lesson => lesson) : [], futureImprovements: formData.futureImprovements ? formData.futureImprovements.split(',').map(improvement => improvement.trim()).filter(improvement => improvement) : [], demoVideo: formData.demoVideo || undefined, screenshots: formData.screenshots ? formData.screenshots.split(',').map(screenshot => screenshot.trim()).filter(screenshot => screenshot) : [], colorScheme: formData.colorScheme, accessibility: formData.accessibility, performance: formData.performance, analytics: formData.analytics }; await apiService.updateProject(selectedProject.id, projectData); console.log('Project updated successfully in database:', selectedProject.id); showProjectSaved(formData.title); } else { // Create new project in database const projectData = { title: formData.title, description: formData.description, content: markdownContent, tags: formData.tags ? formData.tags.split(',').map(tag => tag.trim()).filter(tag => tag) : [], category: formData.category, featured: formData.featured, github: formData.github || undefined, live: formData.live || undefined, published: formData.published, imageUrl: formData.imageUrl || undefined, date: new Date().getFullYear().toString(), difficulty: formData.difficulty, timeToComplete: formData.timeToComplete || undefined, technologies: formData.technologies ? formData.technologies.split(',').map(tech => tech.trim()).filter(tech => tech) : [], challenges: formData.challenges ? formData.challenges.split(',').map(challenge => challenge.trim()).filter(challenge => challenge) : [], lessonsLearned: formData.lessonsLearned ? formData.lessonsLearned.split(',').map(lesson => lesson.trim()).filter(lesson => lesson) : [], futureImprovements: formData.futureImprovements ? formData.futureImprovements.split(',').map(improvement => improvement.trim()).filter(improvement => improvement) : [], demoVideo: formData.demoVideo || undefined, screenshots: formData.screenshots ? formData.screenshots.split(',').map(screenshot => screenshot.trim()).filter(screenshot => screenshot) : [], colorScheme: formData.colorScheme, accessibility: formData.accessibility, performance: formData.performance, analytics: formData.analytics }; await apiService.createProject(projectData); console.log('New project created successfully in database'); showProjectSaved(formData.title); } // Reload projects from database await loadProjects(); resetForm(); } catch (error) { console.error('Error saving project:', error); showError('Fehler beim Speichern', 'Das Projekt konnte nicht gespeichert werden. Bitte versuche es erneut.'); } }; const handleEdit = (project: Project) => { console.log('Editing project:', project); setSelectedProject(project); setFormData({ title: project.title, description: project.description, content: project.content, tags: project.tags.join(', '), category: project.category, featured: project.featured, github: project.github || '', live: project.live || '', published: project.published !== undefined ? project.published : true, imageUrl: project.imageUrl || '', // New 2.0 fields difficulty: project.difficulty || 'Intermediate' as const, timeToComplete: project.timeToComplete || '', technologies: project.technologies ? project.technologies.join(', ') : '', challenges: project.challenges ? project.challenges.join(', ') : '', lessonsLearned: project.lessonsLearned ? project.lessonsLearned.join(', ') : '', futureImprovements: project.futureImprovements ? project.futureImprovements.join(', ') : '', demoVideo: project.demoVideo || '', screenshots: project.screenshots ? project.screenshots.join(', ') : '', colorScheme: project.colorScheme || 'Dark', accessibility: project.accessibility !== undefined ? project.accessibility : true, performance: project.performance || { lighthouse: 90, bundleSize: '50KB', loadTime: '1.5s' }, analytics: project.analytics || { views: 0, likes: 0, shares: 0 } }); setMarkdownContent(project.content); setIsPreview(false); }; const handleDelete = async (projectId: number) => { if (confirm('Are you sure you want to delete this project?')) { try { const project = projects.find(p => p.id === projectId); await apiService.deleteProject(projectId); await loadProjects(); // Reload from database console.log('Project deleted successfully from database:', projectId); if (project) { showProjectDeleted(project.title); } } catch (error) { console.error('Error deleting project:', error); showError('Fehler beim LΓΆschen', 'Das Projekt konnte nicht gelΓΆscht werden. Bitte versuche es erneut.'); } } }; const resetForm = () => { console.log('Resetting form'); setSelectedProject(null); setFormData({ title: '', description: '', content: '', tags: '', category: '', featured: false, github: '', live: '', published: true, imageUrl: '', // New 2.0 fields difficulty: 'Intermediate' as 'Beginner' | 'Intermediate' | 'Advanced' | 'Expert', timeToComplete: '', technologies: '', challenges: '', lessonsLearned: '', futureImprovements: '', demoVideo: '', screenshots: '', colorScheme: 'Dark', accessibility: true, performance: { lighthouse: 90, bundleSize: '50KB', loadTime: '1.5s' }, analytics: { views: 0, likes: 0, shares: 0 } }); setMarkdownContent(''); setIsPreview(false); }; const insertMarkdown = (type: string) => { const textarea = document.getElementById('markdown-editor') as HTMLTextAreaElement; if (!textarea) return; const start = textarea.selectionStart; const end = textarea.selectionEnd; const text = textarea.value; let insertion = ''; let cursorOffset = 0; switch (type) { case 'h1': insertion = `# ${text.substring(start, end) || 'Heading'}`; cursorOffset = 2; break; case 'h2': insertion = `## ${text.substring(start, end) || 'Heading'}`; cursorOffset = 3; break; case 'bold': insertion = `**${text.substring(start, end) || 'bold text'}**`; cursorOffset = 2; break; case 'italic': insertion = `*${text.substring(start, end) || 'italic text'}*`; cursorOffset = 1; break; case 'list': insertion = `- ${text.substring(start, end) || 'list item'}`; cursorOffset = 2; break; case 'link': insertion = `[${text.substring(start, end) || 'link text'}](url)`; cursorOffset = 3; break; case 'image': insertion = `![alt text](image-url)`; cursorOffset = 9; break; case 'code': insertion = `\`${text.substring(start, end) || 'code'}\``; cursorOffset = 1; break; case 'quote': insertion = `> ${text.substring(start, end) || 'quote text'}`; cursorOffset = 2; break; case 'table': insertion = `| Header 1 | Header 2 | Header 3 |\n|----------|----------|----------|\n| Cell 1 | Cell 2 | Cell 3 |\n| Cell 4 | Cell 5 | Cell 6 |`; cursorOffset = 0; break; case 'emoji': insertion = `😊 ${text.substring(start, end) || 'Add your text here'}`; cursorOffset = 2; break; case 'codeblock': insertion = `\`\`\`javascript\n${text.substring(start, end) || '// Your code here'}\n\`\`\``; cursorOffset = 0; break; case 'highlight': insertion = `==${text.substring(start, end) || 'highlighted text'}==`; cursorOffset = 2; break; case 'spoiler': insertion = `||${text.substring(start, end) || 'spoiler text'}||`; cursorOffset = 2; break; case 'callout': insertion = `> [!NOTE]\n> ${text.substring(start, end) || 'This is a callout box'}`; cursorOffset = 0; break; } const newText = text.substring(0, start) + insertion + text.substring(end); setMarkdownContent(newText); // Set cursor position and select the placeholder text for easy editing setTimeout(() => { textarea.focus(); if (type === 'h1' || type === 'h2') { // For headings, select the placeholder text so user can type directly const placeholderStart = start + (type === 'h1' ? 2 : 3); const placeholderEnd = start + insertion.length; textarea.setSelectionRange(placeholderStart, placeholderEnd); } else { // For other elements, position cursor appropriately textarea.setSelectionRange(start + insertion.length - cursorOffset, start + insertion.length - cursorOffset); } }, 0); }; const handleProjectImageUpload = (e: React.ChangeEvent) => { const files = e.target.files; if (!files || files.length === 0) return; const file = files[0]; if (file) { // Simulate image upload - in production you'd upload to a real service const imageUrl = URL.createObjectURL(file); setFormData(prev => ({ ...prev, imageUrl })); } }; const handleImageUpload = (e: React.ChangeEvent) => { const files = e.target.files; if (!files || files.length === 0) return; const file = files[0]; if (file) { // Create a more descriptive image URL for better organization const imageName = file.name.replace(/\.[^/.]+$/, ""); // Remove file extension const imageUrl = URL.createObjectURL(file); const textarea = document.getElementById('markdown-editor') as HTMLTextAreaElement; if (!textarea) return; const start = textarea.selectionStart; const text = textarea.value; // Insert image with better alt text and a newline for spacing const insertion = `\n![${imageName}](${imageUrl})\n`; const newText = text.substring(0, start) + insertion + text.substring(start); setMarkdownContent(newText); // Focus back to textarea and position cursor after the image setTimeout(() => { textarea.focus(); const newCursorPos = start + insertion.length; textarea.setSelectionRange(newCursorPos, newCursorPos); }, 0); } }; // Project Templates const projectTemplates = { 'Web App': { title: 'Web Application', description: 'A modern web application with responsive design and advanced features.', content: `# Web Application ## πŸš€ Overview A modern web application built with cutting-edge technologies. ## ✨ Features - **Responsive Design**: Works perfectly on all devices - **Modern UI/UX**: Beautiful and intuitive user interface - **Performance**: Optimized for speed and efficiency - **Security**: Built with security best practices ## πŸ› οΈ Technologies Used - Frontend Framework - Backend Technology - Database - Additional Tools ## πŸ“± Screenshots ![App Screenshot](screenshot-url) ## πŸ”— Links - [Live Demo](demo-url) - [GitHub Repository](github-url) ## πŸ“ˆ Future Improvements - Feature 1 - Feature 2 - Feature 3`, difficulty: 'Intermediate' as 'Beginner' | 'Intermediate' | 'Advanced' | 'Expert', category: 'Web Application', technologies: 'React, Node.js, MongoDB', colorScheme: 'Modern and Clean' }, 'Mobile App': { title: 'Mobile Application', description: 'A cross-platform mobile application with native performance.', content: `# Mobile Application ## πŸ“± Overview A cross-platform mobile application that delivers native performance. ## ✨ Features - **Cross-Platform**: Works on iOS and Android - **Native Performance**: Optimized for mobile devices - **Offline Support**: Works without internet connection - **Push Notifications**: Keep users engaged ## πŸ› οΈ Technologies Used - React Native / Flutter - Backend API - Database - Cloud Services ## πŸ“Έ Screenshots ![Mobile Screenshot](screenshot-url) ## πŸ”— Links - [App Store](app-store-url) - [Play Store](play-store-url) - [GitHub Repository](github-url) ## πŸ“ˆ Future Improvements - Feature 1 - Feature 2 - Feature 3`, difficulty: 'Advanced' as 'Beginner' | 'Intermediate' | 'Advanced' | 'Expert', category: 'Mobile App', technologies: 'React Native, Firebase, Node.js', colorScheme: 'Mobile-First Design' }, 'API Service': { title: 'API Service', description: 'A robust and scalable API service with comprehensive documentation.', content: `# API Service ## πŸ”Œ Overview A robust and scalable API service that powers multiple applications. ## ✨ Features - **RESTful Design**: Follows REST API best practices - **Authentication**: Secure JWT-based authentication - **Rate Limiting**: Prevents abuse and ensures stability - **Comprehensive Docs**: Complete API documentation - **Testing**: Extensive test coverage ## πŸ› οΈ Technologies Used - Backend Framework - Database - Authentication - Testing Tools ## πŸ“š API Endpoints \`\`\` GET /api/users POST /api/users PUT /api/users/:id DELETE /api/users/:id \`\`\` ## πŸ”— Links - [API Documentation](docs-url) - [GitHub Repository](github-url) ## πŸ“ˆ Future Improvements - Feature 1 - Feature 2 - Feature 3`, difficulty: 'Intermediate' as const, category: 'API Development', technologies: 'Node.js, Express, MongoDB', colorScheme: 'Professional and Clean' } }; const applyTemplate = (templateKey: string) => { const template = projectTemplates[templateKey as keyof typeof projectTemplates]; if (template) { setFormData({ ...formData, title: template.title, description: template.description, category: template.category, difficulty: template.difficulty, technologies: template.technologies, colorScheme: template.colorScheme }); setMarkdownContent(template.content); setShowTemplates(false); } }; return (
{/* Header */} Back to Home

Admin Dashboard

Manage your projects with the built-in Markdown editor. Create, edit, and preview your content easily.

{/* Control Buttons */}
setIsProjectsCollapsed(!isProjectsCollapsed)} className="flex items-center space-x-2 px-6 py-3 bg-gradient-to-r from-gray-700 to-gray-800 hover:from-gray-600 hover:to-gray-700 rounded-xl text-white transition-all duration-200 hover:scale-105 border border-gray-600/50 shadow-lg" title={isProjectsCollapsed ? "Show Projects" : "Hide Projects"} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} > {isProjectsCollapsed ? ( <> Show Projects ) : ( <> Hide Projects )} setShowImportExport(!showImportExport)} className="flex items-center space-x-2 px-6 py-3 bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-500 hover:to-blue-600 rounded-xl text-white transition-all duration-200 hover:scale-105 border border-blue-500/50 shadow-lg" title="Import & Export Projects" whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} > Import/Export setShowAnalytics(!showAnalytics)} className="flex items-center space-x-2 px-6 py-3 bg-gradient-to-r from-green-600 to-green-700 hover:from-green-500 hover:to-green-600 rounded-xl text-white transition-all duration-200 hover:scale-105 border border-green-500/50 shadow-lg" title="Analytics Dashboard" whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} > Analytics
{/* Import/Export Section */} {showImportExport && ( )} {/* Analytics Section */} {showAnalytics && ( )}
{/* Projects List */}

Projects

{projects.map((project) => (
handleEdit(project)} >

{project.title}

{project.description}

{project.category}
))}
{/* Editor */}

{selectedProject ? 'Edit Project' : 'New Project'}

{selectedProject && ( )}
{/* Project Templates Modal */} {showTemplates && ( setShowTemplates(false)} > e.stopPropagation()} >

πŸš€ Project Templates

{Object.entries(projectTemplates).map(([key, template]) => ( applyTemplate(key)} >

{template.title}

{template.description}

Difficulty: {template.difficulty}
Category: {template.category}
Tech: {template.technologies}
))}

Templates provide a starting point for your projects. Customize them as needed!

)} {!isPreview ? (
{/* Basic Info */}
setFormData({...formData, title: e.target.value})} className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="Project title" />
{/* Links */}
setFormData({...formData, github: e.target.value})} className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="https://github.com/username/repo" />
setFormData({...formData, live: e.target.value})} className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="https://demo.example.com" />
{/* Project Image */}
{formData.imageUrl ? ( Project preview ) : (
{formData.title ? formData.title.split(' ').map(word => word[0]).join('').toUpperCase() : 'P'}
)}

Upload a project image or use auto-generated initials

{/* Advanced Project Details - 2.0 Features */}

Advanced Project Details

{/* Difficulty & Time */}
setFormData({...formData, timeToComplete: e.target.value})} className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="e.g., 2-3 weeks, 1 month" />
{/* Technologies & Color Scheme */}
setFormData({...formData, technologies: e.target.value})} className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="React, TypeScript, Node.js" />
setFormData({...formData, colorScheme: e.target.value})} className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="e.g., Dark theme, Light theme, Colorful" />
{/* Performance Metrics */}
setFormData({ ...formData, performance: {...formData.performance, lighthouse: parseInt(e.target.value)} })} className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="90" />
setFormData({ ...formData, performance: {...formData.performance, bundleSize: e.target.value} })} className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="45KB" />
setFormData({ ...formData, performance: {...formData.performance, loadTime: e.target.value} })} className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" placeholder="1.2s" />
{/* Learning & Challenges */}