- Restructure from single filament table to multi-category product catalog (filamenti, stampaci, ploce, mlaznice, delovi, oprema) - Add shared layout components (SiteHeader, SiteFooter, CategoryNav, Breadcrumb) - Add reusable UI primitives (Badge, Button, Card, Modal, PriceDisplay, EmptyState) - Add catalog components (CatalogPage, ProductTable, ProductGrid, FilamentCard, ProductCard) - Add admin dashboard with sidebar navigation and category management - Add product API endpoints and database migrations - Add SEO pages (politika-privatnosti, uslovi-koriscenja, robots.txt, sitemap.xml) - Fix light mode: gradient text contrast, category nav accessibility, surface tokens, card shadows, CTA section theming
126 lines
4.4 KiB
TypeScript
126 lines
4.4 KiB
TypeScript
'use client';
|
|
|
|
import React from 'react';
|
|
import { Filament } from '@/src/types/filament';
|
|
|
|
interface FilamentRowProps {
|
|
filament: Filament;
|
|
}
|
|
|
|
export function FilamentRow({ filament }: FilamentRowProps) {
|
|
const hasRefill = filament.refill > 0;
|
|
const hasSpool = filament.spulna > 0;
|
|
|
|
// Parse prices from the cena field (format: "3499" or "3499/3999")
|
|
let refillPrice = 3499;
|
|
let spoolPrice = 3999;
|
|
|
|
if (filament.cena) {
|
|
const prices = filament.cena.split('/');
|
|
if (prices.length === 1) {
|
|
refillPrice = parseInt(prices[0]) || 3499;
|
|
spoolPrice = parseInt(prices[0]) || 3999;
|
|
} else if (prices.length === 2) {
|
|
refillPrice = parseInt(prices[0]) || 3499;
|
|
spoolPrice = parseInt(prices[1]) || 3999;
|
|
}
|
|
}
|
|
|
|
const saleActive = filament.sale_active && filament.sale_percentage;
|
|
const saleRefillPrice = saleActive
|
|
? Math.round(refillPrice * (1 - filament.sale_percentage! / 100))
|
|
: refillPrice;
|
|
const saleSpoolPrice = saleActive
|
|
? Math.round(spoolPrice * (1 - filament.sale_percentage! / 100))
|
|
: spoolPrice;
|
|
|
|
return (
|
|
<tr className="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
|
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
|
{filament.tip}
|
|
</td>
|
|
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
|
{filament.finish}
|
|
</td>
|
|
<td className="px-2 sm:px-6 py-4 whitespace-nowrap">
|
|
<div className="flex items-center gap-1 sm:gap-2">
|
|
{filament.boja_hex && (
|
|
<div
|
|
className="w-5 h-5 sm:w-7 sm:h-7 rounded border border-gray-300 dark:border-gray-600 flex-shrink-0"
|
|
style={{ backgroundColor: filament.boja_hex }}
|
|
title={filament.boja_hex}
|
|
/>
|
|
)}
|
|
<span className="text-xs sm:text-sm text-gray-900 dark:text-gray-100">
|
|
{filament.boja}
|
|
</span>
|
|
</div>
|
|
</td>
|
|
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm">
|
|
{hasRefill ? (
|
|
<span className="text-green-600 dark:text-green-400 font-bold">{filament.refill}</span>
|
|
) : (
|
|
<span className="text-gray-400 dark:text-gray-500">0</span>
|
|
)}
|
|
</td>
|
|
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm">
|
|
{hasSpool ? (
|
|
<span className="text-blue-500 dark:text-blue-400 font-bold">{filament.spulna}</span>
|
|
) : (
|
|
<span className="text-gray-400 dark:text-gray-500">0</span>
|
|
)}
|
|
</td>
|
|
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
|
{filament.kolicina}
|
|
</td>
|
|
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm font-bold text-gray-900 dark:text-white">
|
|
{!hasRefill && !hasSpool ? (
|
|
'-'
|
|
) : (
|
|
<>
|
|
{hasRefill && (
|
|
<span
|
|
className={
|
|
saleActive
|
|
? 'line-through text-gray-500 dark:text-gray-400'
|
|
: 'text-green-600 dark:text-green-400'
|
|
}
|
|
>
|
|
{refillPrice.toLocaleString('sr-RS')}
|
|
</span>
|
|
)}
|
|
{hasRefill && saleActive && (
|
|
<span className="text-green-600 dark:text-green-400 font-bold ml-1">
|
|
{saleRefillPrice.toLocaleString('sr-RS')}
|
|
</span>
|
|
)}
|
|
{hasRefill && hasSpool && <span className="mx-1">/</span>}
|
|
{hasSpool && (
|
|
<span
|
|
className={
|
|
saleActive
|
|
? 'line-through text-gray-500 dark:text-gray-400'
|
|
: 'text-blue-500 dark:text-blue-400'
|
|
}
|
|
>
|
|
{spoolPrice.toLocaleString('sr-RS')}
|
|
</span>
|
|
)}
|
|
{hasSpool && saleActive && (
|
|
<span className="text-blue-500 dark:text-blue-400 font-bold ml-1">
|
|
{saleSpoolPrice.toLocaleString('sr-RS')}
|
|
</span>
|
|
)}
|
|
<span className="ml-1 text-gray-600 dark:text-gray-400">RSD</span>
|
|
{saleActive && (
|
|
<span className="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200">
|
|
-{filament.sale_percentage}%
|
|
</span>
|
|
)}
|
|
</>
|
|
)}
|
|
</td>
|
|
</tr>
|
|
);
|
|
}
|