Fix production environment variables

- Remove old Confluence variables
- Add NEXT_PUBLIC_API_URL for API access

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DaX
2025-06-20 00:11:36 +02:00
parent 1a96e5eef6
commit a2252fa923
31 changed files with 4089 additions and 42 deletions

View File

@@ -2,6 +2,7 @@ import React, { useState, useMemo } from 'react';
import { Filament } from '../types/filament';
import { ColorCell } from './ColorCell';
import { getFilamentColor, getColorStyle, getContrastColor } from '../data/bambuLabColors';
import '../styles/select.css';
interface FilamentTableProps {
filaments: Filament[];
@@ -13,13 +14,48 @@ export const FilamentTable: React.FC<FilamentTableProps> = ({ filaments, loading
const [searchTerm, setSearchTerm] = useState('');
const [sortField, setSortField] = useState<keyof Filament>('boja');
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc');
// Filter states
const [filterBrand, setFilterBrand] = useState('');
const [filterTip, setFilterTip] = useState('');
const [filterFinish, setFilterFinish] = useState('');
const [filterStatus, setFilterStatus] = useState('');
// Get unique values for filters
const uniqueBrands = useMemo(() => [...new Set(filaments.map(f => f.brand))].sort(), [filaments]);
const uniqueTips = useMemo(() => [...new Set(filaments.map(f => f.tip))].sort(), [filaments]);
const uniqueFinishes = useMemo(() => [...new Set(filaments.map(f => f.finish))].sort(), [filaments]);
const filteredAndSortedFilaments = useMemo(() => {
let filtered = filaments.filter(filament =>
Object.values(filament).some(value =>
let filtered = filaments.filter(filament => {
// Search filter
const matchesSearch = Object.values(filament).some(value =>
value.toLowerCase().includes(searchTerm.toLowerCase())
)
);
);
// Brand filter
const matchesBrand = !filterBrand || filament.brand === filterBrand;
// Type filter
const matchesTip = !filterTip || filament.tip === filterTip;
// Finish filter
const matchesFinish = !filterFinish || filament.finish === filterFinish;
// Status filter
let matchesStatus = true;
if (filterStatus) {
if (filterStatus === 'new') {
matchesStatus = filament.vakum.toLowerCase().includes('vakuum') && !filament.otvoreno;
} else if (filterStatus === 'opened') {
matchesStatus = filament.otvoreno.toLowerCase().includes('otvorena');
} else if (filterStatus === 'refill') {
matchesStatus = filament.refill.toLowerCase() === 'da';
}
}
return matchesSearch && matchesBrand && matchesTip && matchesFinish && matchesStatus;
});
filtered.sort((a, b) => {
const aValue = a[sortField];
@@ -33,7 +69,7 @@ export const FilamentTable: React.FC<FilamentTableProps> = ({ filaments, loading
});
return filtered;
}, [filaments, searchTerm, sortField, sortOrder]);
}, [filaments, searchTerm, sortField, sortOrder, filterBrand, filterTip, filterFinish, filterStatus]);
const handleSort = (field: keyof Filament) => {
if (sortField === field) {
@@ -62,14 +98,103 @@ export const FilamentTable: React.FC<FilamentTableProps> = ({ filaments, loading
return (
<div className="w-full">
<div className="mb-4">
<input
type="text"
placeholder="Pretraži filamente..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<div className="space-y-4 mb-4">
{/* Search Bar */}
<div>
<input
type="text"
placeholder="Pretraži filamente..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
{/* Filter Row */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{/* Brand Filter */}
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Brend
</label>
<select
value={filterBrand}
onChange={(e) => setFilterBrand(e.target.value)}
className="custom-select w-full px-3 py-2 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Svi brendovi</option>
{uniqueBrands.map(brand => (
<option key={brand} value={brand}>{brand}</option>
))}
</select>
</div>
{/* Type Filter */}
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Tip
</label>
<select
value={filterTip}
onChange={(e) => setFilterTip(e.target.value)}
className="custom-select w-full px-3 py-2 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Svi tipovi</option>
{uniqueTips.map(tip => (
<option key={tip} value={tip}>{tip}</option>
))}
</select>
</div>
{/* Finish Filter */}
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Završna obrada
</label>
<select
value={filterFinish}
onChange={(e) => setFilterFinish(e.target.value)}
className="custom-select w-full px-3 py-2 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Sve obrade</option>
{uniqueFinishes.map(finish => (
<option key={finish} value={finish}>{finish}</option>
))}
</select>
</div>
{/* Status Filter */}
<div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Status
</label>
<select
value={filterStatus}
onChange={(e) => setFilterStatus(e.target.value)}
className="custom-select w-full px-3 py-2 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
<option value="">Svi statusi</option>
<option value="new">Novi (vakuum)</option>
<option value="opened">Otvoreni</option>
<option value="refill">Refill</option>
</select>
</div>
</div>
{/* Clear Filters Button */}
{(filterBrand || filterTip || filterFinish || filterStatus) && (
<button
onClick={() => {
setFilterBrand('');
setFilterTip('');
setFilterFinish('');
setFilterStatus('');
}}
className="text-sm text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300"
>
Obriši filtere
</button>
)}
</div>
<div className="overflow-x-auto">