'use client' import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { colorService } from '@/src/services/api'; import { bambuLabColors, getColorHex } from '@/src/data/bambuLabColorsComplete'; import '@/src/styles/select.css'; interface Color { id: string; name: string; hex: string; cena_refill?: number; cena_spulna?: number; createdAt?: string; updatedAt?: string; } export default function ColorsManagement() { const router = useRouter(); const [colors, setColors] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [editingColor, setEditingColor] = useState(null); const [showAddForm, setShowAddForm] = useState(false); const [darkMode, setDarkMode] = useState(false); const [mounted, setMounted] = useState(false); const [searchTerm, setSearchTerm] = useState(''); const [selectedColors, setSelectedColors] = useState>(new Set()); // 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(() => { // Wait for component to mount to avoid SSR issues with localStorage if (!mounted) return; const token = localStorage.getItem('authToken'); const expiry = localStorage.getItem('tokenExpiry'); if (!token || !expiry || Date.now() > parseInt(expiry)) { window.location.href = '/upadaj'; } }, [mounted]); // Fetch colors const fetchColors = async () => { try { setLoading(true); const colors = await colorService.getAll(); setColors(colors.sort((a: Color, b: Color) => a.name.localeCompare(b.name))); } catch (err) { setError('Greška pri učitavanju boja'); console.error('Fetch error:', err); } finally { setLoading(false); } }; useEffect(() => { fetchColors(); }, []); const handleSave = async (color: Partial) => { try { if (color.id) { await colorService.update(color.id, { name: color.name!, hex: color.hex!, cena_refill: color.cena_refill, cena_spulna: color.cena_spulna }); } else { await colorService.create({ name: color.name!, hex: color.hex!, cena_refill: color.cena_refill, cena_spulna: color.cena_spulna }); } setEditingColor(null); setShowAddForm(false); fetchColors(); } catch (err) { setError('Greška pri čuvanju boje'); console.error('Save error:', err); } }; const handleDelete = async (id: string) => { if (!confirm('Da li ste sigurni da želite obrisati ovu boju?')) { return; } try { await colorService.delete(id); fetchColors(); } catch (err) { setError('Greška pri brisanju boje'); console.error('Delete error:', err); } }; const handleBulkDelete = async () => { if (selectedColors.size === 0) { setError('Molimo izaberite boje za brisanje'); return; } if (!confirm(`Da li ste sigurni da želite obrisati ${selectedColors.size} boja?`)) { return; } try { // Delete all selected colors await Promise.all(Array.from(selectedColors).map(id => colorService.delete(id))); setSelectedColors(new Set()); fetchColors(); } catch (err) { setError('Greška pri brisanju boja'); console.error('Bulk delete error:', err); } }; const toggleColorSelection = (colorId: string) => { const newSelection = new Set(selectedColors); if (newSelection.has(colorId)) { newSelection.delete(colorId); } else { newSelection.add(colorId); } setSelectedColors(newSelection); }; const toggleSelectAll = () => { const filteredColors = colors.filter(color => color.name.toLowerCase().includes(searchTerm.toLowerCase()) || color.hex.toLowerCase().includes(searchTerm.toLowerCase()) ); const allFilteredSelected = filteredColors.every(c => selectedColors.has(c.id)); if (allFilteredSelected) { // Deselect all setSelectedColors(new Set()); } else { // Select all filtered setSelectedColors(new Set(filteredColors.map(c => c.id))); } }; const handleLogout = () => { localStorage.removeItem('authToken'); localStorage.removeItem('tokenExpiry'); router.push('/upadaj'); }; if (loading) { return
Učitavanje...
; } return (
{/* Sidebar */} {/* Main Content */}
Filamenteka

Upravljanje bojama

{!showAddForm && !editingColor && ( )} {selectedColors.size > 0 && ( )} {mounted && ( )}
{error && (
{error}
)} {/* Add Form (stays at top) */} {showAddForm && ( { setShowAddForm(false); }} /> )} {/* Search Bar */}
setSearchTerm(e.target.value)} className="w-full px-4 py-2 pl-10 pr-4 text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:border-blue-500" />
{/* Colors Table */}
{colors .filter(color => color.name.toLowerCase().includes(searchTerm.toLowerCase()) || color.hex.toLowerCase().includes(searchTerm.toLowerCase()) ) .map((color) => ( ))}
{ const filtered = colors.filter(color => color.name.toLowerCase().includes(searchTerm.toLowerCase()) || color.hex.toLowerCase().includes(searchTerm.toLowerCase()) ); return filtered.length > 0 && filtered.every(c => selectedColors.has(c.id)); })()} onChange={toggleSelectAll} className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600" /> Boja Naziv Hex kod Cena Refil Cena Spulna Akcije
toggleColorSelection(color.id)} className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600" />
{color.name} {color.hex} {(color.cena_refill || 3499).toLocaleString('sr-RS')} RSD {(color.cena_spulna || 3999).toLocaleString('sr-RS')} RSD
{/* Edit Modal */} {editingColor && (

Izmeni boju

{ handleSave(color); setEditingColor(null); }} onCancel={() => setEditingColor(null)} isModal={true} />
)}
); } // Color Form Component function ColorForm({ color, onSave, onCancel, isModal = false }: { color: Partial, onSave: (color: Partial) => void, onCancel: () => void, isModal?: boolean }) { const [formData, setFormData] = useState({ name: color.name || '', hex: color.hex || '#000000', cena_refill: color.cena_refill || 3499, cena_spulna: color.cena_spulna || 3999, }); // Check if this is a Bambu Lab predefined color const isBambuLabColor = !!(formData.name && bambuLabColors.hasOwnProperty(formData.name)); const bambuHex = formData.name ? getColorHex(formData.name) : null; const handleChange = (e: React.ChangeEvent) => { const { name, value, type } = e.target; setFormData({ ...formData, [name]: type === 'number' ? parseInt(value) || 0 : value }); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // Use Bambu Lab hex if it's a predefined color const hexToSave = isBambuLabColor && bambuHex ? bambuHex : formData.hex; onSave({ ...color, name: formData.name, hex: hexToSave, cena_refill: formData.cena_refill, cena_spulna: formData.cena_spulna }); }; return (
{!isModal && (

{color.id ? 'Izmeni boju' : 'Dodaj novu boju'}

)}
{isBambuLabColor && (

Bambu Lab predefinisana boja - hex kod se ne može menjati

)}
); }