277 lines
14 KiB
TypeScript
277 lines
14 KiB
TypeScript
"use client";
|
||
|
||
import React, { useState } from 'react';
|
||
import { Product } from '@/types/types';
|
||
import { formatCurrency } from '@/lib/utils';
|
||
import { useCartStore } from '@/lib/cart-store';
|
||
import { ShoppingCart, Heart, Scale, ShieldCheck, Truck, Clock, AlertCircle, Wrench, ChevronDown, Check, Zap, Volume2, ThermometerSun, Settings, ArrowRightLeft, Sun, Mail, Info, Snowflake, CreditCard } from 'lucide-react';
|
||
import { useRouter } from 'next/navigation';
|
||
import Link from 'next/link';
|
||
|
||
interface ProductInfoProps {
|
||
product: Product;
|
||
}
|
||
|
||
export function ProductInfo({ product }: ProductInfoProps) {
|
||
const router = useRouter();
|
||
const addItem = useCartStore((state) => state.addItem);
|
||
|
||
// Wariant
|
||
const hasVariants = product.variants && product.variants.length > 0;
|
||
const defaultVariant = hasVariants ? product.variants![0] : null;
|
||
const [selectedVariant, setSelectedVariant] = useState(defaultVariant);
|
||
const [hoursPerDay, setHoursPerDay] = useState<number>(1);
|
||
|
||
// Aktualnie wybrana cena
|
||
const currentPrice = selectedVariant ? selectedVariant.price : product.price;
|
||
const currentPriceWithInstall = selectedVariant ? selectedVariant.priceWithInstall : product.priceWithInstall;
|
||
const currentPower = selectedVariant ? selectedVariant.power : product.power;
|
||
const currentLabel = selectedVariant ? selectedVariant.label : undefined;
|
||
|
||
const [addedMessage, setAddedMessage] = useState('');
|
||
|
||
// Kalkulator energii
|
||
const costPerKwh = 1.15; // Przykładowy koszt 1 kWh w PLN
|
||
const consumptionCooling = currentPower / 4;
|
||
const consumptionHeating = currentPower / 3.8;
|
||
const costHourCooling = consumptionCooling * costPerKwh;
|
||
const costHourHeating = consumptionHeating * costPerKwh;
|
||
|
||
const monthlyCostCooling = costHourCooling * hoursPerDay * 30;
|
||
const monthlyCostHeating = costHourHeating * hoursPerDay * 30;
|
||
|
||
const handleAddToCart = (withInstall: boolean) => {
|
||
addItem({
|
||
slug: product.slug,
|
||
name: product.name,
|
||
brand: product.brand,
|
||
image: product.image || '/hero.jpg',
|
||
power: currentPower,
|
||
label: currentLabel,
|
||
price: currentPrice,
|
||
priceWithInstall: currentPriceWithInstall || currentPrice,
|
||
withInstall
|
||
});
|
||
|
||
setAddedMessage(withInstall ? 'Dodano z montażem' : 'Dodano do koszyka');
|
||
setTimeout(() => setAddedMessage(''), 3000);
|
||
};
|
||
|
||
return (
|
||
<div className="flex flex-col">
|
||
<div className="flex justify-between items-start mb-2">
|
||
<span className="text-sm font-bold text-text-muted uppercase tracking-wider">{product.brand}</span>
|
||
<div className="flex items-center gap-2 text-text-muted">
|
||
<button className="btn btn-ghost btn-circle btn-sm hover:text-accent" aria-label="Dodaj do listy życzeń">
|
||
<Heart className="w-5 h-5" />
|
||
</button>
|
||
<button className="btn btn-ghost btn-circle btn-sm hover:text-accent" aria-label="Porównaj">
|
||
<ArrowRightLeft className="w-5 h-5" />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h1 className="text-3xl md:text-4xl font-extrabold text-primary font-heading leading-tight mb-4">
|
||
{product.name}
|
||
</h1>
|
||
|
||
{/* Cechy skrócone */}
|
||
{product.features && (
|
||
<div className="flex flex-wrap gap-2 mb-8">
|
||
{product.features.map((feat, idx) => (
|
||
<span key={idx} className="bg-slate-100 text-text-muted text-xs font-semibold px-2.5 py-1 rounded-md border border-border">
|
||
{feat}
|
||
</span>
|
||
))}
|
||
</div>
|
||
)}
|
||
|
||
{/* Wybór Wariantu */}
|
||
{hasVariants && (
|
||
<div className="mb-6">
|
||
<span className="block text-xs font-semibold text-text-muted uppercase tracking-wider mb-3">Wybierz wariant mocy:</span>
|
||
<div className="flex flex-wrap gap-2">
|
||
{product.variants!.map((variant, idx) => (
|
||
<button
|
||
key={idx}
|
||
onClick={() => setSelectedVariant(variant)}
|
||
className={`px-4 py-2 rounded-lg border text-sm font-bold transition-all ${
|
||
selectedVariant?.label === variant.label
|
||
? 'border-primary bg-primary text-white shadow-md'
|
||
: 'border-border bg-white text-text-muted hover:border-primary/50 hover:text-primary'
|
||
}`}
|
||
>
|
||
{variant.label}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Szybka specyfikacja z ikonami */}
|
||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-6 text-sm">
|
||
<div className="flex items-center gap-2 text-primary font-semibold">
|
||
<Snowflake className="w-4 h-4 text-accent" />
|
||
<span>{product.specs?.["Klasa energetyczna chłodzenie/grzanie"]?.split("/")[0]?.trim() || "A++"}</span>
|
||
</div>
|
||
{product.heating !== false && (
|
||
<div className="flex items-center gap-2 text-primary font-semibold">
|
||
<Sun className="w-4 h-4 text-orange-500" />
|
||
<span>{product.specs?.["Klasa energetyczna chłodzenie/grzanie"]?.split("/")[1]?.trim() || "A+"}</span>
|
||
</div>
|
||
)}
|
||
<div className="flex items-center gap-2 text-primary font-semibold">
|
||
<Zap className="w-4 h-4 text-yellow-500" />
|
||
<span>{(currentPower / 4).toFixed(2)} kW/h</span>
|
||
</div>
|
||
<div className="flex items-center gap-2 text-primary font-semibold">
|
||
<Zap className="w-4 h-4 text-yellow-500" />
|
||
<span>{currentPower} kW</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Szczegółowa specyfikacja skrócona (lista) */}
|
||
<ul className="space-y-2.5 mb-8 text-sm text-text-muted">
|
||
<li className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">Wydajność chłodnicza:</strong> {(currentPower).toFixed(2)} kW</span>
|
||
</li>
|
||
{product.heating !== false && (
|
||
<li className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">Wydajność grzewcza:</strong> {(currentPower * 1.1).toFixed(2)} kW</span>
|
||
</li>
|
||
)}
|
||
<li className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">Średnie zużycie energii (chłodzenie/grzanie):</strong> {(consumptionCooling).toFixed(2)} / {(consumptionHeating).toFixed(2)} kW</span>
|
||
</li>
|
||
<li className="flex gap-2 flex-col">
|
||
<div className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">Szacunkowy koszt energii – 1 h (chłodzenie/grzanie):</strong> {costHourCooling.toFixed(2)} / {costHourHeating.toFixed(2)} zł</span>
|
||
</div>
|
||
<div className="ml-3.5 mt-2 p-4 bg-white rounded-xl border border-border shadow-sm inline-block w-full max-w-sm">
|
||
<div className="flex items-center justify-between gap-4 mb-3">
|
||
<span className="text-sm font-medium text-text-muted">Ile godzin dziennie używasz?</span>
|
||
<input
|
||
type="number"
|
||
min="1"
|
||
max="24"
|
||
value={hoursPerDay}
|
||
onChange={(e) => setHoursPerDay(Number(e.target.value) || 1)}
|
||
className="w-16 px-2 py-1.5 text-sm font-bold text-center border border-border rounded-lg outline-none focus:border-primary transition-colors"
|
||
/>
|
||
</div>
|
||
<div className="text-xs text-text-muted leading-relaxed">
|
||
Twój miesięczny koszt wyniesie: <br />
|
||
<strong className="text-primary font-bold">Chłodzenie {monthlyCostCooling.toFixed(2)} zł</strong> / <strong className="text-primary font-bold">Grzanie {monthlyCostHeating.toFixed(2)} zł</strong>
|
||
</div>
|
||
</div>
|
||
</li>
|
||
<li className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">SEER / SCOP:</strong> {product.specs?.["SEER / SCOP"] || "6.10 / 4.00"}</span>
|
||
</li>
|
||
<li className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">Klasa energetyczna (chłodzenie/grzanie):</strong> {product.specs?.["Klasa energetyczna chłodzenie/grzanie"] || "A++ / A+"}</span>
|
||
</li>
|
||
<li className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">Poziom głośności jednostki wewnętrznej:</strong> {product.specs?.["Poziom hałasu min/max (dB)"] || "24–38 dB"}</span>
|
||
</li>
|
||
<li className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">Zakres pracy - chłodzenie:</strong> {product.specs?.["Zakres temperatur zewnętrznych - chłodzenie"] || "-15~43 °C"}</span>
|
||
</li>
|
||
<li className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">Czas gwarancji:</strong> 5 lat</span>
|
||
</li>
|
||
{product.features && (
|
||
<li className="flex gap-2">
|
||
<span className="w-1.5 h-1.5 rounded-full bg-accent mt-2 shrink-0"></span>
|
||
<span><strong className="text-primary font-semibold">Funkcje:</strong> {product.features.join(", ")}</span>
|
||
</li>
|
||
)}
|
||
</ul>
|
||
|
||
{/* Dostępność i Kontakt */}
|
||
<div className="flex items-center gap-6 py-4 border-y border-border mb-8">
|
||
<div className="flex items-center gap-2">
|
||
<div className="w-3.5 h-3.5 rounded-full bg-green-500 shadow-sm shadow-green-200"></div>
|
||
<span className="text-sm font-medium text-primary">Dostępny od ręki</span>
|
||
</div>
|
||
<Link href="/kontakt" className="flex items-center gap-2 text-text-muted hover:text-primary transition-colors">
|
||
<Mail className="w-4 h-4" />
|
||
<span className="text-sm">Zapytaj o produkt</span>
|
||
</Link>
|
||
</div>
|
||
|
||
{/* Ceny i CTA */}
|
||
<div className="bg-slate-50 p-6 rounded-2xl border border-border mb-8 space-y-6">
|
||
|
||
{/* Cena z montażem (Promowana) */}
|
||
{currentPriceWithInstall && (
|
||
<div className="flex flex-col gap-3 pb-6 border-b border-border/50">
|
||
<div className="flex justify-between items-end flex-wrap gap-4">
|
||
<div>
|
||
<span className="flex items-center gap-1 text-text-muted text-xs font-semibold mb-1 uppercase tracking-wider">
|
||
Cena z montażem dla konsumenta (8% VAT) <Info className="w-3 h-3" />
|
||
</span>
|
||
<div className="flex items-baseline gap-2">
|
||
<span className="text-3xl font-extrabold text-primary font-heading">{formatCurrency(currentPriceWithInstall)}</span>
|
||
</div>
|
||
<div className="text-xs text-accent font-medium mt-1">Darmowa wycena</div>
|
||
</div>
|
||
<button onClick={() => handleAddToCart(true)} className="btn btn-primary text-white">
|
||
<ShoppingCart className="w-4 h-4 mr-2" />
|
||
Kup z montażem
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Cena bez montażu */}
|
||
<div className="flex justify-between items-end flex-wrap gap-4">
|
||
<div>
|
||
<span className="block text-text-muted text-xs font-semibold mb-1 uppercase tracking-wider">Cena urządzenia bez montażu (23% VAT)</span>
|
||
<div className="text-xl font-bold text-primary font-heading">{formatCurrency(currentPrice)}</div>
|
||
</div>
|
||
<button onClick={() => handleAddToCart(false)} className="btn btn-outline btn-primary bg-white">
|
||
Do koszyka
|
||
</button>
|
||
</div>
|
||
|
||
{/* Feedback o dodaniu */}
|
||
{addedMessage && (
|
||
<div className="flex items-center gap-2 text-sm font-bold text-green-600 bg-green-50 p-3 rounded-lg border border-green-200 animate-in fade-in slide-in-from-top-2">
|
||
<Check className="w-4 h-4" />
|
||
{addedMessage}. <button onClick={() => router.push('/koszyk')} className="underline hover:text-green-800">Przejdź do koszyka</button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Atuty */}
|
||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||
<div className="flex flex-col items-center text-center p-4 bg-white rounded-xl border border-border">
|
||
<Truck className="w-6 h-6 text-accent mb-2" />
|
||
<span className="text-xs font-bold text-primary">Darmowa dostawa</span>
|
||
<span className="text-[10px] text-text-muted">na terenie Polski</span>
|
||
</div>
|
||
<div className="flex flex-col items-center text-center p-4 bg-white rounded-xl border border-border">
|
||
<ShieldCheck className="w-6 h-6 text-accent mb-2" />
|
||
<span className="text-xs font-bold text-primary">5 lat gwarancji</span>
|
||
<span className="text-[10px] text-text-muted">na urządzenie i montaż</span>
|
||
</div>
|
||
<div className="flex flex-col items-center text-center p-4 bg-white rounded-xl border border-border">
|
||
<Settings className="w-6 h-6 text-accent mb-2" />
|
||
<span className="text-xs font-bold text-primary">Pełne wsparcie</span>
|
||
<span className="text-[10px] text-text-muted">na każdym etapie</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|