From 808ca077fa35eedfa4e2696915f294fca2f3ff8a Mon Sep 17 00:00:00 2001 From: DaX Date: Mon, 23 Jun 2025 22:27:43 +0200 Subject: [PATCH] Major frontend and admin improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frontend changes: - Removed brand filter and column from table - Removed inventory summary grid - Removed stanje (state) and težina (weight) columns - Reorganized filters: Material → Finish → Color - Updated EnhancedFilters component with new filter structure - Removed legend section for storage conditions Admin dashboard changes: - Removed sidebar navigation (Boje option) - Made dashboard full screen - Removed brand column from table - Removed brand field from add/edit form - Updated all boolean columns to use checkmark/X icons - Made color tiles 40% bigger - Added sortable columns functionality - Auto-fill price: 3499 for refill, 3999 for regular Other improvements: - Added BackToTop button component on all pages - Fixed Next.js dialog backdrop CSS error - Updated tests to match new UI structure - Removed obsolete FilamentTable.tsx component - Ensured proper synchronization between admin and frontend 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- __tests__/ui-features.test.ts | 31 ++- app/layout.tsx | 6 +- app/upadaj/colors/page.tsx | 10 +- app/upadaj/dashboard/page.tsx | 190 +++++++++--------- src/components/BackToTop.tsx | 55 +++++ src/components/ColorSwatch.tsx | 6 +- src/components/EnhancedFilters.tsx | 52 ++--- src/components/FilamentTable.tsx | 311 ----------------------------- src/components/FilamentTableV2.tsx | 108 +--------- src/styles/index.css | 8 + 10 files changed, 224 insertions(+), 553 deletions(-) create mode 100644 src/components/BackToTop.tsx delete mode 100644 src/components/FilamentTable.tsx diff --git a/__tests__/ui-features.test.ts b/__tests__/ui-features.test.ts index f887fe6..109b3a5 100644 --- a/__tests__/ui-features.test.ts +++ b/__tests__/ui-features.test.ts @@ -13,12 +13,12 @@ describe('UI Features Tests', () => { }); it('should display color hex in frontend table', () => { - const filamentTablePath = join(process.cwd(), 'src', 'components', 'FilamentTable.tsx'); + const filamentTablePath = join(process.cwd(), 'src', 'components', 'FilamentTableV2.tsx'); const tableContent = readFileSync(filamentTablePath, 'utf-8'); - // Check for color hex display - expect(tableContent).toContain('filament.bojaHex'); - expect(tableContent).toContain('backgroundColor: filament.bojaHex'); + // Check for color display + expect(tableContent).toContain('ColorSwatch'); + expect(tableContent).toContain('color.hex'); }); it('should have checkboxes for boolean fields', () => { @@ -41,28 +41,25 @@ describe('UI Features Tests', () => { expect(adminContent).toContain('step="1"'); }); - it('should have predefined brand options', () => { + it('should have predefined material options', () => { const adminDashboardPath = join(process.cwd(), 'app', 'upadaj', 'dashboard', 'page.tsx'); const adminContent = readFileSync(adminDashboardPath, 'utf-8'); - // Check for brand select dropdown - expect(adminContent).toContain(''); - expect(adminContent).toContain(''); - expect(adminContent).toContain(''); + // Check for material select dropdown + expect(adminContent).toContain(''); + expect(adminContent).toContain(''); + expect(adminContent).toContain(''); }); - it('should have sidebar navigation in admin', () => { + it('should have admin header with navigation', () => { const adminDashboardPath = join(process.cwd(), 'app', 'upadaj', 'dashboard', 'page.tsx'); - const colorsPagePath = join(process.cwd(), 'app', 'upadaj', 'colors', 'page.tsx'); const dashboardContent = readFileSync(adminDashboardPath, 'utf-8'); - const colorsContent = readFileSync(colorsPagePath, 'utf-8'); - // Check for sidebar - expect(dashboardContent).toContain('href="/upadaj/dashboard"'); - expect(dashboardContent).toContain('href="/upadaj/colors"'); - expect(colorsContent).toContain('href="/upadaj/dashboard"'); - expect(colorsContent).toContain('href="/upadaj/colors"'); + // Check for admin header + expect(dashboardContent).toContain('Admin Dashboard'); + expect(dashboardContent).toContain('Nazad na sajt'); + expect(dashboardContent).toContain('Odjava'); }); it('should have Safari-specific select styling', () => { diff --git a/app/layout.tsx b/app/layout.tsx index 51dbdf7..daa3437 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata } from 'next' import '../src/styles/index.css' +import { BackToTop } from '../src/components/BackToTop' export const metadata: Metadata = { title: 'Filamenteka', @@ -42,7 +43,10 @@ export default function RootLayout({ }} /> - {children} + + {children} + + ) } \ No newline at end of file diff --git a/app/upadaj/colors/page.tsx b/app/upadaj/colors/page.tsx index aa76942..5ccb309 100644 --- a/app/upadaj/colors/page.tsx +++ b/app/upadaj/colors/page.tsx @@ -250,14 +250,20 @@ export default function ColorsManagement() { diff --git a/app/upadaj/dashboard/page.tsx b/app/upadaj/dashboard/page.tsx index c571b2e..3323960 100644 --- a/app/upadaj/dashboard/page.tsx +++ b/app/upadaj/dashboard/page.tsx @@ -23,7 +23,8 @@ export default function AdminDashboard() { const [showAddForm, setShowAddForm] = useState(false); const [darkMode, setDarkMode] = useState(false); const [mounted, setMounted] = useState(false); - const [sidebarOpen, setSidebarOpen] = useState(false); + const [sortField, setSortField] = useState(''); + const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc'); // Initialize dark mode - default to true for admin useEffect(() => { @@ -76,6 +77,34 @@ export default function AdminDashboard() { fetchFilaments(); }, []); + // Sorting logic + const handleSort = (field: string) => { + if (sortField === field) { + setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc'); + } else { + setSortField(field); + setSortOrder('asc'); + } + }; + + const sortedFilaments = [...filaments].sort((a, b) => { + if (!sortField) return 0; + + let aVal = a[sortField as keyof FilamentWithId]; + let bVal = b[sortField as keyof FilamentWithId]; + + // Handle null/undefined values + if (aVal === null || aVal === undefined) aVal = ''; + if (bVal === null || bVal === undefined) bVal = ''; + + // Convert to strings for comparison + aVal = String(aVal).toLowerCase(); + bVal = String(bVal).toLowerCase(); + + if (aVal < bVal) return sortOrder === 'asc' ? -1 : 1; + if (aVal > bVal) return sortOrder === 'asc' ? 1 : -1; + return 0; + }); const handleSave = async (filament: Partial) => { try { @@ -122,52 +151,12 @@ export default function AdminDashboard() { return (
-
- {/* Mobile menu button */} - - - {/* Sidebar */} -
-
-

Admin Panel

- -
-
- - {/* Overlay for mobile */} - {sidebarOpen && ( -
setSidebarOpen(false)} - /> - )} - - {/* Main Content */} -
+ {/* Main Content - Full Screen */} +
-

Admin Dashboard

+

Admin Dashboard

{!showAddForm && !editingFilament && ( @@ -290,7 +317,6 @@ export default function AdminDashboard() {
-
); @@ -309,7 +335,7 @@ function FilamentForm({ onCancel: () => void }) { const [formData, setFormData] = useState({ - brand: filament.brand || '', + brand: filament.brand || 'Bambu Lab', // Use existing brand or default to Bambu Lab tip: filament.tip || '', finish: filament.finish || '', boja: filament.boja || '', @@ -318,7 +344,7 @@ function FilamentForm({ vakum: filament.vakum || '', otvoreno: filament.otvoreno || '', kolicina: filament.kolicina || '', - cena: filament.cena || '', + cena: filament.cena || (filament.id ? '' : '3999'), // Default price for new filaments }); const [availableColors, setAvailableColors] = useState>([]); @@ -385,7 +411,9 @@ function FilamentForm({ } else if (name === 'refill') { setFormData({ ...formData, - [name]: checked ? 'Da' : '' + [name]: checked ? 'Da' : '', + // Auto-fill price based on refill status if this is a new filament + ...(filament.id ? {} : { cena: checked ? '3499' : '3999' }) }); } } else { @@ -410,27 +438,6 @@ function FilamentForm({ {filament.id ? 'Izmeni filament' : 'Dodaj novi filament'}
-
- - -
-
@@ -479,7 +485,7 @@ function FilamentForm({ let hexValue = formData.bojaHex; // Only use Bambu Lab colors if BambuLab brand is selected - if (formData.brand === 'BambuLab') { + if (formData.brand === 'Bambu Lab') { const bambuHex = getColorHex(selectedColorName); if (bambuHex !== "#000000") { hexValue = bambuHex; @@ -503,7 +509,7 @@ function FilamentForm({ > {/* Show Bambu Lab colors only when BambuLab brand is selected */} - {formData.brand === 'BambuLab' && formData.finish && colorsByFinish[formData.finish as keyof typeof colorsByFinish] && ( + {formData.brand === 'Bambu Lab' && formData.finish && colorsByFinish[formData.finish as keyof typeof colorsByFinish] && ( {colorsByFinish[formData.finish as keyof typeof colorsByFinish].map(colorName => ( + {availableColors.map(color => (