'use client' import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { filamentService, colorService } from '@/src/services/api'; import { Filament } from '@/src/types/filament'; import { bambuLabColors, colorsByFinish, getColorHex } from '@/src/data/bambuLabColorsComplete'; import '@/src/styles/select.css'; interface FilamentWithId extends Filament { id: string; createdAt?: string; updatedAt?: string; bojaHex?: string; } export default function AdminDashboard() { const router = useRouter(); const [filaments, setFilaments] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [editingFilament, setEditingFilament] = useState(null); const [showAddForm, setShowAddForm] = useState(false); const [darkMode, setDarkMode] = useState(false); const [mounted, setMounted] = useState(false); const [sidebarOpen, setSidebarOpen] = useState(false); // Initialize dark mode - default to true for admin useEffect(() => { setMounted(true); const saved = localStorage.getItem('darkMode'); if (saved !== null) { setDarkMode(JSON.parse(saved)); } else { // Default to dark mode for admin setDarkMode(true); } }, []); useEffect(() => { if (!mounted) return; localStorage.setItem('darkMode', JSON.stringify(darkMode)); if (darkMode) { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } }, [darkMode, mounted]); // Check authentication useEffect(() => { const token = localStorage.getItem('authToken'); const expiry = localStorage.getItem('tokenExpiry'); if (!token || !expiry || Date.now() > parseInt(expiry)) { router.push('/upadaj'); } }, [router]); // Fetch filaments const fetchFilaments = async () => { try { setLoading(true); const filaments = await filamentService.getAll(); setFilaments(filaments); } catch (err) { setError('Greška pri učitavanju filamenata'); console.error('Fetch error:', err); } finally { setLoading(false); } }; useEffect(() => { fetchFilaments(); }, []); const handleSave = async (filament: Partial) => { try { if (filament.id) { await filamentService.update(filament.id, filament); } else { await filamentService.create(filament); } setEditingFilament(null); setShowAddForm(false); fetchFilaments(); } catch (err) { setError('Greška pri čuvanju filamenata'); console.error('Save error:', err); } }; const handleDelete = async (id: string) => { if (!confirm('Da li ste sigurni da želite obrisati ovaj filament?')) { return; } try { await filamentService.delete(id); fetchFilaments(); } catch (err) { setError('Greška pri brisanju filamenata'); console.error('Delete error:', err); } }; const handleLogout = () => { localStorage.removeItem('authToken'); localStorage.removeItem('tokenExpiry'); router.push('/upadaj'); }; if (loading) { return
Učitavanje...
; } return (
{/* Mobile menu button */} {/* Sidebar */} {/* Overlay for mobile */} {sidebarOpen && (
setSidebarOpen(false)} /> )} {/* Main Content */}

Admin Dashboard

{!showAddForm && !editingFilament && ( )} {mounted && ( )}
{error && (
{error}
)} {/* Add/Edit Form */} {(showAddForm || editingFilament) && (
{ setEditingFilament(null); setShowAddForm(false); }} />
)} {/* Filaments Table */}
{filaments.map((filament) => ( ))}
Brand Tip Finish Boja Refill Vakum Otvoreno Količina Cena Akcije
{filament.brand} {filament.tip} {filament.finish}
{filament.boja} {filament.bojaHex && (
)}
{filament.refill} {filament.vakum} {filament.otvoreno} {filament.kolicina} {filament.cena}
); } // Filament Form Component function FilamentForm({ filament, filaments, onSave, onCancel }: { filament: Partial, filaments: FilamentWithId[], onSave: (filament: Partial) => void, onCancel: () => void }) { const [formData, setFormData] = useState({ brand: filament.brand || '', tip: filament.tip || '', finish: filament.finish || '', boja: filament.boja || '', bojaHex: filament.bojaHex || '', refill: filament.refill || '', vakum: filament.vakum || '', otvoreno: filament.otvoreno || '', kolicina: filament.kolicina || '', cena: filament.cena || '', }); const [availableColors, setAvailableColors] = useState>([]); // Load colors from API useEffect(() => { const loadColors = async () => { try { const colors = await colorService.getAll(); setAvailableColors(colors.sort((a: any, b: any) => a.name.localeCompare(b.name))); } catch (error) { console.error('Error loading colors:', error); // Fallback to colors from existing filaments const existingColors = [...new Set(filaments.map(f => f.boja).filter(Boolean))]; const colorObjects = existingColors.map((color, idx) => ({ id: `existing-${idx}`, name: color, hex: filaments.find(f => f.boja === color)?.bojaHex || '#000000' })); setAvailableColors(colorObjects.sort((a, b) => a.name.localeCompare(b.name))); } }; loadColors(); // Reload colors when window gets focus (in case user added colors in another tab) const handleFocus = () => loadColors(); window.addEventListener('focus', handleFocus); return () => window.removeEventListener('focus', handleFocus); }, [filaments]); // Update form when filament prop changes useEffect(() => { setFormData({ brand: filament.brand || '', tip: filament.tip || '', finish: filament.finish || '', boja: filament.boja || '', bojaHex: filament.bojaHex || '', refill: filament.refill || '', vakum: filament.vakum || '', otvoreno: filament.otvoreno || '', kolicina: filament.kolicina || '', cena: filament.cena || '', }); }, [filament]); const handleChange = (e: React.ChangeEvent) => { const { name, value, type } = e.target; if (type === 'checkbox') { const checked = (e.target as HTMLInputElement).checked; if (name === 'vakum') { setFormData({ ...formData, [name]: checked ? 'vakuum' : '' }); } else if (name === 'otvoreno') { setFormData({ ...formData, [name]: checked ? 'otvorena' : '' }); } else if (name === 'refill') { setFormData({ ...formData, [name]: checked ? 'Da' : '' }); } } else { setFormData({ ...formData, [name]: value }); } }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); onSave({ ...filament, ...formData }); }; return (

{filament.id ? 'Izmeni filament' : 'Dodaj novi filament'}

{formData.bojaHex && ( {formData.bojaHex} )}
{/* Cena and Checkboxes on same line */}
{/* Checkboxes grouped together horizontally */}
); }