'use client'; import { useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; interface Post { slug: string; title: string; date: string; tags: string[]; summary: string; content: string; } interface Folder { type: 'folder'; name: string; path: string; children: (Post | Folder)[]; } interface Post { type: 'post'; slug: string; title: string; date: string; tags: string[]; summary: string; content: string; } type Node = Post | Folder; export default function AdminPage() { const [isAuthenticated, setIsAuthenticated] = useState(false); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [nodes, setNodes] = useState([]); const [currentPath, setCurrentPath] = useState([]); const [newPost, setNewPost] = useState({ title: '', date: new Date().toISOString().split('T')[0], tags: '', summary: '', content: '', }); const [newFolderName, setNewFolderName] = useState(''); const [isDragging, setIsDragging] = useState(false); const router = useRouter(); useEffect(() => { // Check if already authenticated const auth = localStorage.getItem('adminAuth'); if (auth === 'true') { setIsAuthenticated(true); loadContent(); } }, []); const loadContent = async () => { try { const response = await fetch('/api/posts'); const data = await response.json(); setNodes(data); } catch (error) { console.error('Error loading content:', error); } }; const handleLogin = (e: React.FormEvent) => { e.preventDefault(); if (username === 'admin' && password === 'admin') { setIsAuthenticated(true); localStorage.setItem('adminAuth', 'true'); loadContent(); } else { alert('Invalid credentials'); } }; const handleLogout = () => { setIsAuthenticated(false); localStorage.removeItem('adminAuth'); }; const handleCreatePost = async (e: React.FormEvent) => { e.preventDefault(); try { const response = await fetch('/api/admin/posts', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ ...newPost, tags: newPost.tags.split(',').map(tag => tag.trim()), path: currentPath.join('/'), }), }); if (response.ok) { setNewPost({ title: '', date: new Date().toISOString().split('T')[0], tags: '', summary: '', content: '', }); loadContent(); } else { alert('Error creating post'); } } catch (error) { console.error('Error creating post:', error); alert('Error creating post'); } }; const handleCreateFolder = async (e: React.FormEvent) => { e.preventDefault(); if (!newFolderName.trim()) { alert('Please enter a folder name'); return; } try { const response = await fetch('/api/admin/folders', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: newFolderName, path: currentPath.join('/'), }), }); if (response.ok) { setNewFolderName(''); loadContent(); } else { alert('Error creating folder'); } } catch (error) { console.error('Error creating folder:', error); alert('Error creating folder'); } }; // Get current directory contents const getCurrentNodes = (): Node[] => { let currentNodes: Node[] = nodes; for (const segment of currentPath) { const folder = currentNodes.find( (n) => n.type === 'folder' && n.name === segment ) as Folder | undefined; if (folder) { currentNodes = folder.children; } else { break; } } return currentNodes; }; const currentNodes = getCurrentNodes(); // Breadcrumbs const breadcrumbs = [ { name: 'Root', path: [] }, ...currentPath.map((name, idx) => ({ name, path: currentPath.slice(0, idx + 1), })), ]; const handleDragOver = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragging(true); }, []); const handleDragLeave = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); }, []); const handleDrop = useCallback(async (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); const files = Array.from(e.dataTransfer.files); const markdownFiles = files.filter(file => file.name.endsWith('.md')); if (markdownFiles.length === 0) { alert('Please drop only Markdown files'); return; } for (const file of markdownFiles) { try { const content = await file.text(); const formData = new FormData(); formData.append('file', file); formData.append('path', currentPath.join('/')); const response = await fetch('/api/admin/upload', { method: 'POST', body: formData, }); if (!response.ok) { throw new Error(`Failed to upload ${file.name}`); } } catch (error) { console.error(`Error uploading ${file.name}:`, error); alert(`Error uploading ${file.name}`); } } loadContent(); }, [currentPath]); if (!isAuthenticated) { return (

Admin Login

setUsername(e.target.value)} className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2" required />
setPassword(e.target.value)} className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2" required />
); } return (

Admin Dashboard

{/* Breadcrumb Navigation */} {/* Create Folder Form */}

Create New Folder

setNewFolderName(e.target.value)} placeholder="Folder name" className="flex-1 rounded-md border border-gray-300 px-3 py-2" required />
{/* Drag and Drop Zone */}

Drag and drop Markdown files here

Files will be uploaded to: {currentPath.join('/') || 'root'}

{/* Create Post Form */}

Create New Post

setNewPost({ ...newPost, title: e.target.value })} className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2" required />
setNewPost({ ...newPost, date: e.target.value })} className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2" required />
setNewPost({ ...newPost, tags: e.target.value })} className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2" placeholder="tag1, tag2, tag3" />