Add admin sorting options and prevent zero quantity filament creation
- Add sorting dropdown with Serbian labels (alphabetical, date-based, quantity) - Fix Safari dropdown styling with custom-select class - Add validation to prevent adding filaments with 0 quantity - Improve sort dropdown layout and error handling 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: DaX <noreply@anthropic.com>
This commit is contained in:
@@ -158,7 +158,21 @@ export default function AdminDashboard() {
|
|||||||
if (aVal === null || aVal === undefined) aVal = '';
|
if (aVal === null || aVal === undefined) aVal = '';
|
||||||
if (bVal === null || bVal === undefined) bVal = '';
|
if (bVal === null || bVal === undefined) bVal = '';
|
||||||
|
|
||||||
// Convert to strings for comparison
|
// Handle date fields
|
||||||
|
if (sortField === 'created_at' || sortField === 'updated_at') {
|
||||||
|
const aDate = new Date(String(aVal));
|
||||||
|
const bDate = new Date(String(bVal));
|
||||||
|
return sortOrder === 'asc' ? aDate.getTime() - bDate.getTime() : bDate.getTime() - aDate.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle numeric fields
|
||||||
|
if (sortField === 'kolicina' || sortField === 'refill' || sortField === 'spulna') {
|
||||||
|
const aNum = Number(aVal) || 0;
|
||||||
|
const bNum = Number(bVal) || 0;
|
||||||
|
return sortOrder === 'asc' ? aNum - bNum : bNum - aNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// String comparison for other fields
|
||||||
aVal = String(aVal).toLowerCase();
|
aVal = String(aVal).toLowerCase();
|
||||||
bVal = String(bVal).toLowerCase();
|
bVal = String(bVal).toLowerCase();
|
||||||
|
|
||||||
@@ -355,19 +369,54 @@ export default function AdminDashboard() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Search Bar */}
|
{/* Search Bar and Sorting */}
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<div className="relative">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
<input
|
{/* Search Input */}
|
||||||
type="text"
|
<div className="relative">
|
||||||
placeholder="Pretraži po tipu, finishu, boji ili ceni..."
|
<input
|
||||||
value={searchTerm}
|
type="text"
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
placeholder="Pretraži po tipu, finishu, boji ili ceni..."
|
||||||
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"
|
value={searchTerm}
|
||||||
/>
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
<svg className="absolute left-3 top-2.5 h-5 w-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
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"
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
/>
|
||||||
</svg>
|
<svg className="absolute left-3 top-2.5 h-5 w-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sort Dropdown */}
|
||||||
|
<div>
|
||||||
|
<select
|
||||||
|
value={`${sortField || 'boja'}-${sortOrder || 'asc'}`}
|
||||||
|
onChange={(e) => {
|
||||||
|
try {
|
||||||
|
const [field, order] = e.target.value.split('-');
|
||||||
|
if (field && order) {
|
||||||
|
setSortField(field);
|
||||||
|
setSortOrder(order as 'asc' | 'desc');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Sort change error:', error);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="custom-select w-full px-3 py-2 text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:border-blue-500"
|
||||||
|
>
|
||||||
|
<option value="boja-asc">Sortiraj po: Boja (A-Z)</option>
|
||||||
|
<option value="boja-desc">Sortiraj po: Boja (Z-A)</option>
|
||||||
|
<option value="tip-asc">Sortiraj po: Tip (A-Z)</option>
|
||||||
|
<option value="tip-desc">Sortiraj po: Tip (Z-A)</option>
|
||||||
|
<option value="finish-asc">Sortiraj po: Finish (A-Z)</option>
|
||||||
|
<option value="finish-desc">Sortiraj po: Finish (Z-A)</option>
|
||||||
|
<option value="created_at-desc">Sortiraj po: Poslednje dodano</option>
|
||||||
|
<option value="created_at-asc">Sortiraj po: Prvo dodano</option>
|
||||||
|
<option value="updated_at-desc">Sortiraj po: Poslednje ažurirano</option>
|
||||||
|
<option value="updated_at-asc">Sortiraj po: Prvo ažurirano</option>
|
||||||
|
<option value="kolicina-desc">Sortiraj po: Količina (visoka-niska)</option>
|
||||||
|
<option value="kolicina-asc">Sortiraj po: Količina (niska-visoka)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -637,6 +686,12 @@ function FilamentForm({
|
|||||||
// Calculate total quantity
|
// Calculate total quantity
|
||||||
const totalQuantity = formData.refill + formData.spulna;
|
const totalQuantity = formData.refill + formData.spulna;
|
||||||
|
|
||||||
|
// Prevent adding filaments with 0 quantity
|
||||||
|
if (totalQuantity === 0) {
|
||||||
|
alert('Količina mora biti veća od 0. Dodajte refill ili spulna.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Use the prices from the form (which can be edited)
|
// Use the prices from the form (which can be edited)
|
||||||
const refillPrice = formData.cena_refill;
|
const refillPrice = formData.cena_refill;
|
||||||
const spoolPrice = formData.cena_spulna;
|
const spoolPrice = formData.cena_spulna;
|
||||||
|
|||||||
Reference in New Issue
Block a user