style: update pricing section layout and remove stats from WhyUs
This commit is contained in:
+137
-1
@@ -7,7 +7,7 @@ import { Testimonials } from "@/components/sections/Testimonials";
|
|||||||
import { BlogPreview } from "@/components/sections/BlogPreview";
|
import { BlogPreview } from "@/components/sections/BlogPreview";
|
||||||
import { CtaBanner } from "@/components/sections/CtaBanner";
|
import { CtaBanner } from "@/components/sections/CtaBanner";
|
||||||
import { companyDetails } from "@/content/company";
|
import { companyDetails } from "@/content/company";
|
||||||
import { Wrench, Phone, ArrowRight } from "lucide-react";
|
import { Wrench, Phone, ArrowRight, Thermometer, Wind, Zap, Calendar, Check } from "lucide-react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
@@ -177,6 +177,142 @@ export default function Home() {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<BlogPreview />
|
<BlogPreview />
|
||||||
|
|
||||||
|
{/* Cennik usług */}
|
||||||
|
{/* Cennik usług */}
|
||||||
|
<section className="bg-white py-16 px-4">
|
||||||
|
<div className="bg-slate-50 max-w-7xl mx-auto rounded-[2.5rem] p-6 sm:p-10 lg:p-14">
|
||||||
|
<div className="max-w-6xl mx-auto flex flex-col gap-8">
|
||||||
|
|
||||||
|
{/* Header (Sekcja hero nad kartami) */}
|
||||||
|
<div className="mb-2">
|
||||||
|
<div className="inline-flex items-center gap-1.5 text-[10px] font-bold text-accent uppercase tracking-widest mb-6 bg-accent/5 border border-accent/20 px-3 py-1.5 rounded-full">
|
||||||
|
<Check className="size-3.5" />
|
||||||
|
Cennik usług
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl sm:text-5xl font-extrabold text-primary font-heading leading-tight mb-4">
|
||||||
|
Serwis i czyszczenie klimatyzacji –<br />już od <span className="underline decoration-accent underline-offset-4">300 zł</span>
|
||||||
|
</h2>
|
||||||
|
<p className="text-text-muted text-sm sm:text-base max-w-2xl leading-relaxed">
|
||||||
|
Profesjonalna obsługa, certyfikowani specjaliści i szybki czas reakcji na terenie całego Wrocławia. Zadbaj o czyste powietrze i wydajność swoich urządzeń.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Cards Grid */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
|
||||||
|
{/* Card 1: Czyszczenie (2 columns wide) */}
|
||||||
|
<div className="bg-white md:col-span-2 p-8 flex flex-col relative overflow-hidden rounded-2xl shadow-sm border border-border">
|
||||||
|
<div className="hidden md:block absolute top-0 right-0 w-48 h-48 bg-slate-50"></div>
|
||||||
|
<div className="relative z-10 flex flex-col md:flex-row gap-6 mb-12">
|
||||||
|
<div className="size-12 bg-accent flex items-center justify-center shrink-0 border border-accent/10 rounded-lg">
|
||||||
|
<Thermometer className="size-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div className="pr-4 md:pr-40">
|
||||||
|
<h3 className="text-xl font-bold text-primary font-heading mb-3">Czyszczenie i odgrzybianie</h3>
|
||||||
|
<p className="text-sm text-text-muted leading-relaxed">Kompleksowe czyszczenie jednostki wewnętrznej i zewnętrznej, dezynfekcja chemiczna, odgrzybianie parowe, czyszczenie filtrów oraz sprawdzenie odpływu skroplin. Gwarantuje czyste powietrze bez alergenów.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="relative z-10 border-t border-border pt-5 mt-auto">
|
||||||
|
<p className="text-[10px] font-bold uppercase tracking-widest text-text-muted mb-1">Cena usługi</p>
|
||||||
|
<p className="text-xl font-extrabold text-primary">od 300 zł</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Card 2: Przegląd techniczny */}
|
||||||
|
<div className="bg-white p-8 flex flex-col rounded-2xl shadow-sm border border-border">
|
||||||
|
<div className="flex flex-col gap-6 mb-12">
|
||||||
|
<div className="size-12 bg-slate-100 flex items-center justify-center shrink-0 border border-slate-200 rounded-lg">
|
||||||
|
<Wind className="size-5 text-accent" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-bold text-primary font-heading mb-3">Przegląd techniczny</h3>
|
||||||
|
<p className="text-sm text-text-muted leading-relaxed">Sprawdzenie parametrów pracy, kontrola szczelności układu, pomiar ciśnień roboczych i temperatur.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="border-t border-border pt-5 mt-auto">
|
||||||
|
<p className="text-[10px] font-bold uppercase tracking-widest text-text-muted mb-1">Cena usługi</p>
|
||||||
|
<p className="text-xl font-extrabold text-primary">od 150 zł</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Card 3: Uzupełnienie czynnika */}
|
||||||
|
<div className="bg-white p-8 flex flex-col rounded-2xl shadow-sm border border-border">
|
||||||
|
<div className="flex flex-col gap-6 mb-12">
|
||||||
|
<div className="size-12 bg-slate-100 flex items-center justify-center shrink-0 border border-slate-200 rounded-lg">
|
||||||
|
<Zap className="size-5 text-accent" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-bold text-primary font-heading mb-3">Uzupełnienie czynnika</h3>
|
||||||
|
<p className="text-sm text-text-muted leading-relaxed">Lokalizacja nieszczelności, próba ciśnieniowa azotem, próżniowanie układu i dobicie czynnika chłodniczego.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="border-t border-border pt-5 mt-auto">
|
||||||
|
<p className="text-[10px] font-bold uppercase tracking-widest text-text-muted mb-1">Cena usługi</p>
|
||||||
|
<p className="text-sm font-extrabold text-primary">Wycena indywidualna</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Card 4: Naprawa usterek */}
|
||||||
|
<div className="bg-white p-8 flex flex-col rounded-2xl shadow-sm border border-border">
|
||||||
|
<div className="flex flex-col gap-6 mb-12">
|
||||||
|
<div className="size-12 bg-slate-100 flex items-center justify-center shrink-0 border border-slate-200 rounded-lg">
|
||||||
|
<Wrench className="size-5 text-accent" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-bold text-primary font-heading mb-3">Naprawa usterek</h3>
|
||||||
|
<p className="text-sm text-text-muted leading-relaxed">Diagnoza awarii, wymiana uszkodzonych podzespołów elektroniki, sprężarek, wentylatorów.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="border-t border-border pt-5 mt-auto">
|
||||||
|
<p className="text-[10px] font-bold uppercase tracking-widest text-text-muted mb-1">Cena usługi</p>
|
||||||
|
<p className="text-sm font-extrabold text-primary">Wycena indywidualna</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Card 5: Serwis sezonowy (Dark card) */}
|
||||||
|
<div className="bg-[#1a2332] p-8 flex flex-col border border-[#1a2332] shadow-sm rounded-2xl">
|
||||||
|
<div className="flex flex-col gap-6 mb-12">
|
||||||
|
<div className="size-12 bg-slate-800 flex items-center justify-center shrink-0 border border-slate-700 rounded-lg">
|
||||||
|
<Calendar className="size-5 text-accent" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-bold text-white font-heading mb-3">Serwis sezonowy / Abonament</h3>
|
||||||
|
<p className="text-sm text-white/60 leading-relaxed">Regularna opieka nad instalacją przed sezonem letnim i zimowym. Priorytetowy czas reakcji w przypadku awarii.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="border-t border-white/10 pt-5 mt-auto">
|
||||||
|
<Link href="/kontakt" className="inline-flex items-center gap-2 text-xs font-bold text-white hover:text-white/80 transition-colors">
|
||||||
|
Zapytaj o pakiety <ArrowRight className="size-4" />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Card 6: Gotowy na świeże powietrze? (Full width) */}
|
||||||
|
<div className="bg-white md:col-span-3 p-8 md:p-10 flex flex-col lg:flex-row items-start lg:items-center justify-between gap-8 border-l-[6px] border-accent rounded-2xl shadow-sm">
|
||||||
|
<div className="max-w-2xl">
|
||||||
|
<h3 className="text-2xl font-bold text-primary font-heading mb-3">Gotowy na świeże powietrze?</h3>
|
||||||
|
<p className="text-sm text-text-muted leading-relaxed">Nasi certyfikowani technicy są dostępni od poniedziałku do soboty. Zarezerwuj termin już dziś, aby uniknąć kolejek w sezonie.</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-4 shrink-0 w-full lg:w-auto">
|
||||||
|
<Link href="/kontakt" className="w-full sm:w-auto">
|
||||||
|
<button className="w-full sm:w-auto flex justify-center items-center gap-2 px-6 py-3.5 bg-accent text-white font-bold text-sm hover:bg-accent/90 transition-colors rounded-xl">
|
||||||
|
Umów serwis <Calendar className="size-4" />
|
||||||
|
</button>
|
||||||
|
</Link>
|
||||||
|
<a href={`tel:${companyDetails.phoneRaw}`} className="w-full sm:w-auto">
|
||||||
|
<button className="w-full sm:w-auto flex justify-center items-center gap-2 px-6 py-3.5 bg-white text-primary border border-border font-bold text-sm hover:bg-slate-50 transition-colors rounded-xl">
|
||||||
|
<Phone className="size-4" /> Zadzwoń do nas
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<CtaBanner bgVariant="accent-light" />
|
<CtaBanner bgVariant="accent-light" />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ export function AwariaClient() {
|
|||||||
<label className="text-xs font-medium text-primary mb-1 block">Marka *</label>
|
<label className="text-xs font-medium text-primary mb-1 block">Marka *</label>
|
||||||
<select
|
<select
|
||||||
required value={brand} onChange={e => { setBrand(e.target.value); setErrorCode(''); }}
|
required value={brand} onChange={e => { setBrand(e.target.value); setErrorCode(''); }}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none bg-white"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none bg-white"
|
||||||
>
|
>
|
||||||
<option value="">Wybierz markę...</option>
|
<option value="">Wybierz markę...</option>
|
||||||
{BRANDS.map(b => <option key={b} value={b}>{b}</option>)}
|
{BRANDS.map(b => <option key={b} value={b}>{b}</option>)}
|
||||||
@@ -238,17 +238,17 @@ export function AwariaClient() {
|
|||||||
<label className="text-xs font-medium text-primary mb-1 block">Model (opcjonalnie)</label>
|
<label className="text-xs font-medium text-primary mb-1 block">Model (opcjonalnie)</label>
|
||||||
<input
|
<input
|
||||||
value={model} onChange={e => setModel(e.target.value)}
|
value={model} onChange={e => setModel(e.target.value)}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none"
|
||||||
placeholder="Np. Gree Pular, LG Artcool 3,5 kW..."
|
placeholder="Np. Gree Pular, LG Artcool 3,5 kW..."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs font-medium text-primary mb-1 block">Na gwarancji?</label>
|
<label className="text-xs font-medium text-primary mb-1 block">Na gwarancji?</label>
|
||||||
<select
|
<select
|
||||||
value={warranty} onChange={e => setWarranty(e.target.value)}
|
value={warranty} onChange={e => setWarranty(e.target.value)}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none bg-white"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none bg-white"
|
||||||
>
|
>
|
||||||
<option value="">Nie wiem</option>
|
<option value="">Nie wiem</option>
|
||||||
<option value="tak">Tak</option>
|
<option value="tak">Tak</option>
|
||||||
@@ -259,7 +259,7 @@ export function AwariaClient() {
|
|||||||
<label className="text-xs font-medium text-primary mb-1 block">Ostatni serwis</label>
|
<label className="text-xs font-medium text-primary mb-1 block">Ostatni serwis</label>
|
||||||
<select
|
<select
|
||||||
value={lastService} onChange={e => setLastService(e.target.value)}
|
value={lastService} onChange={e => setLastService(e.target.value)}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none bg-white"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none bg-white"
|
||||||
>
|
>
|
||||||
<option value="">Nie pamiętam</option>
|
<option value="">Nie pamiętam</option>
|
||||||
<option value="<1rok">Mniej niż rok temu</option>
|
<option value="<1rok">Mniej niż rok temu</option>
|
||||||
@@ -304,7 +304,7 @@ export function AwariaClient() {
|
|||||||
<input
|
<input
|
||||||
value={errorCode}
|
value={errorCode}
|
||||||
onChange={e => setErrorCode(e.target.value)}
|
onChange={e => setErrorCode(e.target.value)}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none"
|
||||||
placeholder="Np. E1, F3, CH05..."
|
placeholder="Np. E1, F3, CH05..."
|
||||||
/>
|
/>
|
||||||
{errorHint && (
|
{errorHint && (
|
||||||
@@ -322,7 +322,7 @@ export function AwariaClient() {
|
|||||||
<textarea
|
<textarea
|
||||||
value={description} onChange={e => setDescription(e.target.value)}
|
value={description} onChange={e => setDescription(e.target.value)}
|
||||||
rows={3}
|
rows={3}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none resize-none"
|
className="w-full rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none resize-none"
|
||||||
placeholder="Opisz kiedy się pojawił problem, jak często występuje, czy jest jakiś charakterystyczny dźwięk..."
|
placeholder="Opisz kiedy się pojawił problem, jak często występuje, czy jest jakiś charakterystyczny dźwięk..."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -340,14 +340,14 @@ export function AwariaClient() {
|
|||||||
<input
|
<input
|
||||||
type="date" value={preferredDate} onChange={e => setPreferredDate(e.target.value)}
|
type="date" value={preferredDate} onChange={e => setPreferredDate(e.target.value)}
|
||||||
min={new Date().toISOString().split('T')[0]}
|
min={new Date().toISOString().split('T')[0]}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="text-xs font-medium text-primary mb-1 block">Godzina</label>
|
<label className="text-xs font-medium text-primary mb-1 block">Godzina</label>
|
||||||
<select
|
<select
|
||||||
value={preferredTime} onChange={e => setPreferredTime(e.target.value)}
|
value={preferredTime} onChange={e => setPreferredTime(e.target.value)}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none bg-white"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none bg-white"
|
||||||
>
|
>
|
||||||
<option value="">Dowolna</option>
|
<option value="">Dowolna</option>
|
||||||
<option value="8:00-10:00">8:00 – 10:00</option>
|
<option value="8:00-10:00">8:00 – 10:00</option>
|
||||||
@@ -371,7 +371,7 @@ export function AwariaClient() {
|
|||||||
<label className="text-xs font-medium text-primary mb-1 block">Imię i nazwisko *</label>
|
<label className="text-xs font-medium text-primary mb-1 block">Imię i nazwisko *</label>
|
||||||
<input
|
<input
|
||||||
required value={name} onChange={e => setName(e.target.value)}
|
required value={name} onChange={e => setName(e.target.value)}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none"
|
||||||
placeholder="Jan Kowalski"
|
placeholder="Jan Kowalski"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -379,7 +379,7 @@ export function AwariaClient() {
|
|||||||
<label className="text-xs font-medium text-primary mb-1 block">Telefon *</label>
|
<label className="text-xs font-medium text-primary mb-1 block">Telefon *</label>
|
||||||
<input
|
<input
|
||||||
required type="tel" value={phone} onChange={e => setPhone(e.target.value)}
|
required type="tel" value={phone} onChange={e => setPhone(e.target.value)}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none"
|
||||||
placeholder="+48 600 000 000"
|
placeholder="+48 600 000 000"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -388,7 +388,7 @@ export function AwariaClient() {
|
|||||||
<label className="text-xs font-medium text-primary mb-1 block">Miasto *</label>
|
<label className="text-xs font-medium text-primary mb-1 block">Miasto *</label>
|
||||||
<select
|
<select
|
||||||
required value={city} onChange={e => setCity(e.target.value)}
|
required value={city} onChange={e => setCity(e.target.value)}
|
||||||
className="w-full border border-border rounded-xl px-3 py-2.5 text-sm focus:border-accent outline-none bg-white"
|
className="w-full h-[42px] rounded-xl px-3 py-2.5 text-sm border border-border focus:border-accent outline-none bg-white"
|
||||||
>
|
>
|
||||||
<option value="">Wybierz miasto...</option>
|
<option value="">Wybierz miasto...</option>
|
||||||
{['Wrocław', 'Legnica', 'Wałbrzych', 'Jelenia Góra', 'Lubin', 'Głogów', 'Świdnica', 'Dzierżoniów', 'Oleśnica', 'Oława', 'Trzebnica', 'Środa Śląska', 'Siechnice', 'Inne'].map(c => (
|
{['Wrocław', 'Legnica', 'Wałbrzych', 'Jelenia Góra', 'Lubin', 'Głogów', 'Świdnica', 'Dzierżoniów', 'Oleśnica', 'Oława', 'Trzebnica', 'Środa Śląska', 'Siechnice', 'Inne'].map(c => (
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ export function Header() {
|
|||||||
{/* CTA Button */}
|
{/* CTA Button */}
|
||||||
<div className="hidden lg:flex items-center gap-3">
|
<div className="hidden lg:flex items-center gap-3">
|
||||||
<Link href="/zgloszenie-awarii">
|
<Link href="/zgloszenie-awarii">
|
||||||
<button className="flex items-center gap-1.5 px-4 py-2 bg-red-500 text-white rounded-xl font-bold text-sm hover:bg-red-600 transition-colors whitespace-nowrap">
|
<button className="flex items-center gap-1.5 px-4 py-2 bg-red-500 text-white rounded-[var(--radius-field)] font-bold text-sm hover:bg-red-600 transition-colors whitespace-nowrap">
|
||||||
<Wrench className="size-4" />
|
<Wrench className="size-4" />
|
||||||
Zgłoś awarię
|
Zgłoś awarię
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -43,19 +43,7 @@ export function WhyUs() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stats Counters Grid */}
|
|
||||||
<div className="grid grid-cols-2 gap-6 mt-6 border-t border-border pt-8">
|
|
||||||
{companyDetails.stats.map((stat, idx) => (
|
|
||||||
<div key={idx} className="flex flex-col">
|
|
||||||
<span className="text-3xl md:text-4xl font-extrabold text-primary font-heading">
|
|
||||||
{stat.value}
|
|
||||||
</span>
|
|
||||||
<span className="text-xs md:text-sm text-text-muted mt-1 leading-snug">
|
|
||||||
{stat.label}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right Column: Advantages Grid */}
|
{/* Right Column: Advantages Grid */}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Image from 'next/image';
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import {
|
import {
|
||||||
ArrowLeft, Phone, ShoppingCart, GitCompare, Check,
|
ArrowLeft, Phone, ShoppingCart, GitCompare, Check,
|
||||||
Thermometer, Volume2, Zap, Wind, Star, Info
|
Thermometer, Volume2, Zap, Wind, Star, Info, Eye, X
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { Product } from '@/content/products';
|
import { Product } from '@/content/products';
|
||||||
import { useCartStore } from '@/lib/cart-store';
|
import { useCartStore } from '@/lib/cart-store';
|
||||||
@@ -58,11 +58,21 @@ function parseMoc(val: string): number {
|
|||||||
const TABS = ['Opis', 'Specyfikacja', 'Montaż'] as const;
|
const TABS = ['Opis', 'Specyfikacja', 'Montaż'] as const;
|
||||||
type Tab = typeof TABS[number];
|
type Tab = typeof TABS[number];
|
||||||
|
|
||||||
|
function seededViews(slug: string): number {
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < slug.length; i++) {
|
||||||
|
hash = (hash * 31 + slug.charCodeAt(i)) >>> 0;
|
||||||
|
}
|
||||||
|
return 18 + (hash % 50);
|
||||||
|
}
|
||||||
|
|
||||||
export function ProductPageClient({ product, seriesProducts, companyPhone, companyPhoneRaw }: Props) {
|
export function ProductPageClient({ product, seriesProducts, companyPhone, companyPhoneRaw }: Props) {
|
||||||
const [currentProduct, setCurrentProduct] = useState(product);
|
const [currentProduct, setCurrentProduct] = useState(product);
|
||||||
const [activeTab, setActiveTab] = useState<Tab>('Opis');
|
const [activeTab, setActiveTab] = useState<Tab>('Opis');
|
||||||
const [godziny, setGodziny] = useState(8);
|
const [godziny, setGodziny] = useState(8);
|
||||||
const [cartState, setCartState] = useState<'idle' | 'added' | 'cart'>('idle');
|
const [cartState, setCartState] = useState<'idle' | 'added' | 'cart'>('idle');
|
||||||
|
const [showViewsBanner, setShowViewsBanner] = useState(true);
|
||||||
|
const viewsCount = seededViews(currentProduct.slug);
|
||||||
|
|
||||||
const variants = getProductVariants(currentProduct.slug);
|
const variants = getProductVariants(currentProduct.slug);
|
||||||
|
|
||||||
@@ -475,6 +485,22 @@ export function ProductPageClient({ product, seriesProducts, companyPhone, compa
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{showViewsBanner && (
|
||||||
|
<div className="fixed bottom-6 left-6 z-50 flex items-center gap-3 bg-white border border-amber-200 shadow-lg rounded-xl px-4 py-3 max-w-xs animate-in slide-in-from-left-4 duration-300">
|
||||||
|
<Eye className="size-4 text-amber-500 shrink-0" />
|
||||||
|
<p className="text-sm text-gray-800">
|
||||||
|
W ostatnich 30 dniach interesuje się tym produktem <span className="font-bold">{viewsCount}</span> osób.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowViewsBanner(false)}
|
||||||
|
className="text-gray-400 hover:text-gray-600 transition-colors shrink-0 ml-1"
|
||||||
|
aria-label="Zamknij"
|
||||||
|
>
|
||||||
|
<X className="size-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user