feat: refactor calculator room logic, update pricing, add dynamic prepositions

This commit is contained in:
MichalC
2026-07-05 21:22:09 +02:00
parent 59fd9a9b97
commit dbbf35a401
6 changed files with 349 additions and 128 deletions
+6 -6
View File
@@ -71,7 +71,7 @@ export default async function MiastoPage({ params }: Props) {
{/* HERO */}
<HeroSection
eyebrow={`Klimatyzacja ${city.name} · Dolny Śląsk · F-Gaz`}
title={`Montaż klimatyzacji w ${city.nameDopelniacz}`}
title={`Montaż klimatyzacji ${city.przyimek} ${city.nameDopelniacz}`}
subtitle={city.heroSubtitle}
ctaText="Zamów bezpłatną wycenę"
ctaLink="/kontakt"
@@ -95,7 +95,7 @@ export default async function MiastoPage({ params }: Props) {
Klimatyzacja {city.name}
</span>
<h2 className="text-2xl md:text-3xl font-bold text-primary font-heading mt-2 mb-4">
Profesjonalny montaż klimatyzacji w {city.nameDopelniacz}
Profesjonalny montaż klimatyzacji {city.przyimek} {city.nameDopelniacz}
</h2>
<p className="text-text-muted leading-relaxed mb-4">{city.introText}</p>
<p className="text-text-muted leading-relaxed">{city.localFacts}</p>
@@ -106,7 +106,7 @@ export default async function MiastoPage({ params }: Props) {
<Clock className="size-5 text-accent shrink-0 mt-0.5" />
<div>
<p className="font-semibold text-primary text-sm">Czas montażu</p>
<p className="text-text-muted text-sm mt-1">Standardowy montaż split w {city.nameDopelniacz} trwa 4–8 godzin. Multisplit — 1–2 dni robocze.</p>
<p className="text-text-muted text-sm mt-1">Standardowy montaż split {city.przyimek} {city.nameDopelniacz} trwa 4–8 godzin. Multisplit — 1–2 dni robocze.</p>
</div>
</div>
<div className="p-5 rounded-xl bg-slate-50 border border-border flex gap-4 items-start">
@@ -144,7 +144,7 @@ export default async function MiastoPage({ params }: Props) {
<ProcessSteps
steps={acProcessSteps}
eyebrow="Jak Działamy"
title={`Montaż klimatyzacji w ${city.nameDopelniacz} — krok po kroku`}
title={`Montaż klimatyzacji ${city.przyimek} ${city.nameDopelniacz} — krok po kroku`}
subtitle="Od pierwszego kontaktu do przekazania gotowej instalacji. Każdy etap pod kontrolą."
/>
@@ -161,7 +161,7 @@ export default async function MiastoPage({ params }: Props) {
Pompy ciepła {city.name}
</div>
<h2 className="text-2xl md:text-3xl font-bold text-white font-heading leading-tight mb-4">
Pompa ciepła w {city.nameDopelniacz}
Pompa ciepła {city.przyimek} {city.nameDopelniacz}
</h2>
<p className="text-white/80 leading-relaxed mb-6">{city.heatPumpTeaser}</p>
<Link href="/pompy-ciepla">
@@ -243,7 +243,7 @@ export default async function MiastoPage({ params }: Props) {
{/* KOŃCOWE CTA */}
<CtaBanner
title={`Potrzebujesz klimatyzacji w ${city.nameDopelniacz}?`}
title={`Potrzebujesz klimatyzacji ${city.przyimek} ${city.nameDopelniacz}?`}
subtitle="Odpowiemy w ciągu godziny i umówimy bezpłatny audyt w dogodnym terminie."
ctaText="Zadzwoń lub napisz"
ctaLink="/kontakt"
+107 -97
View File
@@ -38,7 +38,7 @@ function estimateInstall(pipes: string, rooms: number): { min: number; max: numb
return { min: base + pipeExtra, max: base + pipeExtra + 600 };
}
const STEPS = ['Typ', 'Pomieszczenie', 'Konfiguracja', 'Instalacja', 'Budżet'] as const;
const STEPS = ['Typ', 'Pomieszczenie', 'Instalacja', 'Budżet'] as const;
export function KalkulatorClient({ products }: Props) {
const [deviceType, setDeviceType] = useState<'klimatyzacja' | 'pompa'>('klimatyzacja');
@@ -46,21 +46,42 @@ export function KalkulatorClient({ products }: Props) {
const [pumpForm, setPumpForm] = useState({ name: '', phone: '', city: '', message: '' });
const [step, setStep] = useState(0);
const [building, setBuilding] = useState('apartment');
const [m2, setM2] = useState(25);
const [pomieszczenia, setPomieszczenia] = useState<{ nazwa: string; m2: number }[]>([
{ nazwa: 'Pokój 1', m2: 20 }
]);
const [floor, setFloor] = useState('middle'); // ground | middle | top
const [sun, setSun] = useState('south'); // north | east | south | west
const [systemType, setSystemType] = useState<'auto' | 'scienne' | 'multisplit'>('auto');
const [rooms, setRooms] = useState(1);
const addRoom = () => {
if (pomieszczenia.length < 5) {
setPomieszczenia(prev => [...prev, { nazwa: `Pokój ${prev.length + 1}`, m2: 15 }]);
}
};
const removeRoom = (i: number) => {
if (pomieszczenia.length > 1) {
setPomieszczenia(prev => prev.filter((_, idx) => idx !== i));
}
};
const updateRoom = (i: number, m2: number) => {
setPomieszczenia(prev => prev.map((r, idx) => idx === i ? { ...r, m2 } : r));
};
const [pipes, setPipes] = useState('medium'); // short(<3m) | medium(3-6m) | long(6-10m) | verylong(>10m)
const [budget, setBudget] = useState(8000);
const [showResults, setShowResults] = useState(false);
const [preferredBrand, setPreferredBrand] = useState('');
const requiredPower = useMemo(() => calculatePower(m2, floor, sun, building), [m2, floor, sun, building]);
const totalM2 = pomieszczenia.reduce((sum, p) => sum + p.m2, 0);
const rooms = pomieszczenia.length;
const requiredPower = useMemo(() =>
pomieszczenia.reduce((sum, p) => sum + calculatePower(p.m2, floor, sun, building), 0),
[pomieszczenia, floor, sun, building]
);
const requiredPowerRounded = Math.round(requiredPower * 10) / 10;
const installCost = useMemo(() => estimateInstall(pipes, rooms), [pipes, rooms]);
const category = systemType === 'auto' ? (rooms === 1 ? 'scienne' : 'multisplit') : systemType;
const category = rooms === 1 ? 'scienne' : 'multisplit';
const results = useMemo(() => {
if (!showResults || deviceType === 'pompa') return [];
@@ -151,8 +172,8 @@ export function KalkulatorClient({ products }: Props) {
</h1>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
{[
{ label: 'Wymagana moc', value: `${requiredPower} kW` },
{ label: 'Powierzchnia', value: `${m2} m²` },
{ label: 'Wymagana moc', value: `${requiredPowerRounded} kW` },
{ label: 'Powierzchnia', value: `${totalM2} m²` },
{ label: 'Typ instalacji', value: category === 'scienne' ? 'Split (1 pokój)' : `Multisplit (${rooms} pokoje)` },
{ label: 'Szac. montaż', value: `${installCost.min.toLocaleString('pl-PL')}–${installCost.max.toLocaleString('pl-PL')} zł` },
].map((s, i) => (
@@ -410,35 +431,80 @@ export function KalkulatorClient({ products }: Props) {
</div>
</div>
<div className="flex flex-col gap-1.5">
<div className="flex items-center justify-between">
<span className="text-xs text-text-muted">Powierzchnia</span>
<span className="text-xs font-bold text-primary bg-accent/10 px-2 py-0.5 rounded-md">{m2} m²</span>
</div>
<div className="relative h-5 flex items-center">
<div className="absolute w-full h-1.5 bg-slate-200 rounded-full" />
<div
className="absolute h-1.5 bg-accent rounded-full"
style={{ width: `${((m2 - 10) / 90) * 100}%` }}
/>
<input
type="range" min={10} max={100} step={5} value={m2}
onChange={e => setM2(Number(e.target.value))}
className="absolute w-full h-1.5 opacity-0 cursor-pointer z-10"
/>
<div
className="absolute size-4 bg-white border-2 border-accent rounded-full shadow-md pointer-events-none"
style={{ left: `calc(${((m2 - 10) / 90) * 100}% - 8px)` }}
/>
</div>
<div className="flex justify-between text-xs text-text-muted">
<span>10 m²</span>
<span>100 m²</span>
</div>
<div className="mt-3 p-3 bg-blue-50 rounded-xl text-sm text-blue-700 font-medium">
Wymagana moc: ok. <strong>{requiredPower} kW</strong>
<span className="text-xs font-normal ml-2">(dla {m2} m²)</span>
</div>
{/* Lista pomieszczeń */}
<div className="flex flex-col gap-3">
{pomieszczenia.map((p, i) => (
<div key={i} className="bg-slate-50 rounded-xl border border-border p-4">
<div className="flex items-center justify-between mb-3">
<span className="text-sm font-semibold text-primary">{p.nazwa}</span>
{pomieszczenia.length > 1 && (
<button
onClick={() => removeRoom(i)}
className="text-xs text-red-400 hover:text-red-600 transition-colors"
>
Usuń
</button>
)}
</div>
<div className="flex flex-col gap-1.5">
<div className="flex items-center justify-between">
<span className="text-xs text-text-muted">Powierzchnia</span>
<span className="text-xs font-bold text-primary bg-accent/10 px-2 py-0.5 rounded-md">{p.m2} m²</span>
</div>
<div className="relative h-5 flex items-center">
<div className="absolute w-full h-1.5 bg-slate-200 rounded-full" />
<div
className="absolute h-1.5 bg-accent rounded-full"
style={{ width: `${((p.m2 - 5) / 95) * 100}%` }}
/>
<input
type="range" min={5} max={100} step={5} value={p.m2}
onChange={e => updateRoom(i, Number(e.target.value))}
className="absolute w-full h-1.5 opacity-0 cursor-pointer z-10"
/>
<div
className="absolute size-4 bg-white border-2 border-accent rounded-full shadow-md pointer-events-none"
style={{ left: `calc(${((p.m2 - 5) / 95) * 100}% - 8px)` }}
/>
</div>
<div className="flex justify-between text-xs text-text-muted">
<span>5 m²</span>
<span>100 m²</span>
</div>
{(() => {
const mocPokoju = Math.round(calculatePower(p.m2, floor, sun, building) * 10) / 10;
const dostepneMoce = [2.5, 3.5, 5.0, 7.0];
const zalecana = dostepneMoce.reduce((prev, curr) =>
Math.abs(curr - mocPokoju) < Math.abs(prev - mocPokoju) ? curr : prev
);
return (
<div className="mt-2 flex items-center justify-between bg-white border border-border rounded-lg px-3 py-2">
<span className="text-xs text-text-muted">Zalecana moc jednostki</span>
<span className="text-sm font-bold text-accent">{zalecana} kW</span>
</div>
);
})()}
</div>
</div>
))}
</div>
{pomieszczenia.length < 5 && (
<button
onClick={addRoom}
className="flex items-center gap-2 text-sm text-accent font-semibold hover:text-accent/80 transition-colors border border-dashed border-accent/40 rounded-xl px-4 py-3 w-full justify-center"
>
+ Dodaj kolejne pomieszczenie
</button>
)}
<div className="p-3 bg-accent/10 rounded-xl">
<p className="text-sm text-accent font-semibold">
Łączna wymagana moc: ok. <strong>{requiredPowerRounded} kW</strong>
<span className="text-xs font-normal text-text-muted ml-2">
({pomieszczenia.length === 1 ? 'klimatyzator split' : `multisplit ${pomieszczenia.length}+1`}, łącznie {totalM2} m²)
</span>
</p>
</div>
<div>
@@ -513,64 +579,8 @@ export function KalkulatorClient({ products }: Props) {
</div>
)}
{/* Krok 2: Konfiguracja */}
{/* Krok 2: Instalacja */}
{step === 2 && (
<div className="flex flex-col gap-6">
<div className="flex items-center gap-3 mb-2">
<div className="size-10 rounded-xl bg-purple-50 flex items-center justify-center">
<Thermometer className="size-5 text-purple-600" />
</div>
<div>
<h2 className="text-lg font-bold text-primary font-heading">Konfiguracja</h2>
<p className="text-xs text-text-muted">Ilość pomieszczeń i typ instalacji</p>
</div>
</div>
<div>
<label className="text-sm font-semibold text-primary mb-3 block">Wybierz typ systemu</label>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-2">
{[
{ value: 'auto', label: 'Dobierz automatycznie' },
{ value: 'scienne', label: 'Split (1 agregat = 1 pokój)' },
{ value: 'multisplit', label: 'Multisplit (1 agregat = wiele)' },
].map(o => (
<button key={o.value} onClick={() => setSystemType(o.value as 'auto'|'scienne'|'multisplit')}
className={`py-2 px-3 rounded-xl text-sm font-semibold border-2 transition-all ${systemType === o.value ? 'border-accent bg-accent text-white' : 'border-border bg-white text-primary hover:border-accent'}`}>
{o.label}
</button>
))}
</div>
</div>
<div>
<label className="text-sm font-semibold text-primary mb-3 block">Ile pomieszczeń chcesz chłodzić?</label>
<div className="grid grid-cols-2 gap-3">
{[
{ value: 1, label: '1 pomieszczenie', sub: 'Pojedynczy pokój', icon: '🏠' },
{ value: 2, label: '2 pomieszczenia', sub: 'Dwa pokoje', icon: '🏡' },
{ value: 3, label: '3 pomieszczenia', sub: 'Trzy pokoje', icon: '🏘️' },
{ value: 4, label: '4-5 pomieszczeń', sub: 'Wiele pokoi', icon: '🏗️' },
].map(o => (
<button key={o.value} onClick={() => setRooms(o.value)}
className={`p-4 rounded-xl border-2 text-left transition-all ${rooms === o.value ? 'border-accent bg-accent/5' : 'border-border hover:border-accent'}`}>
<span className="text-2xl mb-2 block">{o.icon}</span>
<p className="text-sm font-bold text-primary">{o.label}</p>
<p className="text-xs text-text-muted">{o.sub}</p>
</button>
))}
</div>
</div>
<div className="p-3 bg-slate-50 rounded-xl text-xs text-text-muted">
{category === 'scienne'
? '✅ Wybrano: Klimatyzator split — jedna jednostka wewnętrzna i jedna zewnętrzna. Dedykowane dla jednego pokoju.'
: `✅ Wybrano: System multisplit — jedna jednostka zewnętrzna obsłuży ${rooms} jednostki wewnętrzne. Lepsza estetyka na zewnątrz budynku.`}
</div>
</div>
)}
{/* Krok 3: Instalacja */}
{step === 3 && (
<div className="flex flex-col gap-6">
<div className="flex items-center gap-3 mb-2">
<div className="size-10 rounded-xl bg-orange-50 flex items-center justify-center">
@@ -628,8 +638,8 @@ export function KalkulatorClient({ products }: Props) {
</div>
)}
{/* Krok 4: Budżet */}
{step === 4 && (
{/* Krok 3: Budżet */}
{step === 3 && (
<div className="flex flex-col gap-6">
<div className="flex items-center gap-3 mb-2">
<div className="size-10 rounded-xl bg-green-50 flex items-center justify-center">
@@ -684,7 +694,7 @@ export function KalkulatorClient({ products }: Props) {
</div>
<div className="p-3 bg-blue-50 rounded-xl text-xs text-blue-700">
💡 Podsumowanie: szukamy klimatyzatora <strong>{category === 'scienne' ? 'split ściennego' : 'multisplit'}</strong> o mocy ok. <strong>{requiredPower} kW</strong> w cenie do <strong>{(budget * 0.75).toLocaleString('pl-PL')} zł</strong>
💡 Podsumowanie: szukamy klimatyzatora <strong>{category === 'scienne' ? 'split ściennego' : 'multisplit'}</strong> o mocy ok. <strong>{requiredPowerRounded} kW</strong> w cenie do <strong>{(budget * 0.75).toLocaleString('pl-PL')} zł</strong>
</div>
<div>
+153
View File
@@ -0,0 +1,153 @@
import Link from "next/link";
import { Wrench, Thermometer, Wind, Zap, Calendar, Phone, Check } from "lucide-react";
import { companyDetails } from "@/content/company";
export function HomeServices() {
return (
<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-7xl mx-auto flex flex-col gap-8">
<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">
Montaż, serwis i czyszczenie klimatyzacji –<br />już od <span className="underline decoration-accent underline-offset-4">150 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: Montaż klimatyzacji */}
<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">Montaż klimatyzacji</h3>
<p className="text-sm text-text-muted leading-relaxed">Profesjonalny montaż urządzeń split i multisplit. Zapewniamy estetykę wykonania i pełne uruchomienie.</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 1400 zł</p>
</div>
</div>
{/* Card 2: Czyszczenie */}
<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">
<Thermometer className="size-5 text-accent" />
</div>
<div>
<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, dezynfekcja chemiczna, odgrzybianie parowe, czyszczenie filtró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-xl font-extrabold text-primary">od 250 zł</p>
</div>
</div>
{/* Card 3: 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.</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 4: 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, 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-xl font-extrabold text-primary">od 180 zł</p>
</div>
</div>
{/* Card 5: 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 6: 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">
<p className="text-[10px] font-bold uppercase tracking-widest text-white/60 mb-1">Cena usługi</p>
<p className="text-xl font-extrabold text-white">od 199 zł / rok</p>
</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>
);
}
+19 -1
View File
@@ -1,4 +1,5 @@
export interface CityData {
przyimek: string;
slug: string;
name: string;
nameDopelniacz: string;
@@ -20,6 +21,7 @@ export interface CityData {
export const dolnySlaskCities: CityData[] = [
{
przyimek: "we",
slug: "wroclaw",
name: "Wrocław",
nameDopelniacz: "Wrocławiu",
@@ -29,7 +31,7 @@ export const dolnySlaskCities: CityData[] = [
distanceFromHQ: "siedziba firmy",
lat: 51.1079,
lng: 17.0385,
heroImage: "https://images.unsplash.com/photo-1585155784229-aff921ccfa22?w=1600&q=80",
heroImage: "/images/cities/wroclaw.webp",
seoTitle: "Klimatyzacja Wrocław — Montaż i Serwis | ThermCool",
seoDescription: "Montaż klimatyzacji we Wrocławiu od specjalistów z uprawnieniami F-Gaz. Bezpłatny audyt, split i multisplit, serwis gwarancyjny. Zadzwoń po wycenę!",
heroSubtitle: "Profesjonalny montaż klimatyzacji we Wrocławiu — split, multisplit, kasetonowe. Bezpłatny audyt, estetyczna instalacja, pełna gwarancja.",
@@ -39,6 +41,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Planujesz ogrzewanie pompy ciepła we Wrocławiu? Pomagamy w doborze, montażu i uzyskaniu dofinansowania z programu Czyste Powietrze. Realizujemy instalacje powietrze-woda na terenie całego Wrocławia i powiatu wrocławskiego.",
},
{
przyimek: "w",
slug: "legnica",
name: "Legnica",
nameDopelniacz: "Legnicy",
@@ -58,6 +61,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Interesuje Cię pompa ciepła w Legnicy? Dobieramy urządzenia dopasowane do zapotrzebowania budynku, pomagamy uzyskać dofinansowanie z Czystego Powietrza i realizujemy kompletną instalację powietrze-woda.",
},
{
przyimek: "w",
slug: "walbrzych",
name: "Wałbrzych",
nameDopelniacz: "Wałbrzychu",
@@ -77,6 +81,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Wałbrzychu to inwestycja szczególnie opłacalna — wyższe położenie i chłodniejszy klimat sprawiają że urządzenia pracują wydajniej. Pomożemy w doborze, montażu i uzyskaniu dotacji z Czystego Powietrza.",
},
{
przyimek: "w",
slug: "jelenia-gora",
name: "Jelenia Góra",
nameDopelniacz: "Jeleniej Górze",
@@ -96,6 +101,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Jeleniej Górze — region górski to idealne warunki dla nowoczesnych pomp ciepła, które pracują wydajnie nawet w niskich temperaturach. Realizujemy instalacje z pełną pomocą w uzyskaniu dofinansowania.",
},
{
przyimek: "w",
slug: "lubin",
name: "Lubin",
nameDopelniacz: "Lubinie",
@@ -115,6 +121,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Lubinie — właściciele domów jednorodzinnych w rejonie Lubina coraz chętniej wymieniają kotły gazowe i węglowe na pompy ciepła. Pomagamy w całym procesie — od audytu przez montaż po dotację.",
},
{
przyimek: "w",
slug: "glogow",
name: "Głogów",
nameDopelniacz: "Głogowie",
@@ -134,6 +141,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Głogowie i powiecie głogowskim — pomagamy właścicielom domów jednorodzinnych przejść z ogrzewania węglowego na ekologiczne i tańsze w eksploatacji pompy ciepła powietrze-woda.",
},
{
przyimek: "w",
slug: "swidnica",
name: "Świdnica",
nameDopelniacz: "Świdnicy",
@@ -153,6 +161,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Świdnicy i powiecie świdnickim — realizujemy instalacje powietrze-woda z pełnym wsparciem w procesie aplikacji o dofinansowanie z programu Czyste Powietrze.",
},
{
przyimek: "w",
slug: "dzierzoniow",
name: "Dzierżoniów",
nameDopelniacz: "Dzierżoniowie",
@@ -172,6 +181,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Dzierżoniowie — dobieramy urządzenia dostosowane do wielkości i izolacji budynku. Pomagamy w uzyskaniu dotacji z Czystego Powietrza, co znacząco obniża koszt inwestycji.",
},
{
przyimek: "w",
slug: "bielawa",
name: "Bielawa",
nameDopelniacz: "Bielawie",
@@ -191,6 +201,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Bielawie — dla właścicieli domów jednorodzinnych to szansa na uniezależnienie się od rosnących cen gazu i węgla. Realizujemy instalacje z pomocą w dotacjach z Czystego Powietrza.",
},
{
przyimek: "w",
slug: "olesnica",
name: "Oleśnica",
nameDopelniacz: "Oleśnicy",
@@ -210,6 +221,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Oleśnicy — bliskość Wrocławia i dobra dostępność naszego serwisu sprawiają że obsługa instalacji jest wyjątkowo komfortowa. Realizujemy instalacje powietrze-woda z pełnym pakietem dofinansowania.",
},
{
przyimek: "w",
slug: "olawa",
name: "Oława",
nameDopelniacz: "Oławie",
@@ -229,6 +241,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Oławie — realizujemy instalacje dla domów jednorodzinnych w Oławie i całym powiecie oławskim. Krótki dojazd to też sprawny serwis przez cały okres użytkowania urządzenia.",
},
{
przyimek: "w",
slug: "strzelin",
name: "Strzelin",
nameDopelniacz: "Strzelinie",
@@ -248,6 +261,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Strzelinie — powiat strzeliński to rejon gdzie wiele domów nadal ogrzewa się węglem. Pompa ciepła to ekologiczna i ekonomiczna alternatywa, a dofinansowanie z Czystego Powietrza czyni ją realnie dostępną.",
},
{
przyimek: "w",
slug: "sroda-slaska",
name: "Środa Śląska",
nameDopelniacz: "Środzie Śląskiej",
@@ -267,6 +281,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Środzie Śląskiej — przy nowych domach jednorodzinnych w tej okolicy pompa ciepła jest często wybierana jako podstawowe źródło ogrzewania. Pomagamy w całym procesie inwestycji.",
},
{
przyimek: "w",
slug: "trzebnica",
name: "Trzebnica",
nameDopelniacz: "Trzebnicy",
@@ -286,6 +301,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Trzebnicy — obsługujemy zarówno prywatne domy jak i większe obiekty. Bliskość Wrocławia to szybki serwis i krótkie czasy reakcji przez cały okres użytkowania pompy.",
},
{
przyimek: "w",
slug: "siechnice",
name: "Siechnice",
nameDopelniacz: "Siechnicach",
@@ -305,6 +321,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Pompa ciepła w Siechnicach — przy nowych domach w tej gminie pompa ciepła jest standardowym wyborem. Realizujemy instalacje powietrze-woda i gruntowe, doradzamy w wyborze optymalnego rozwiązania dla danej działki.",
},
{
przyimek: "w",
slug: "opole",
name: "Opole",
nameDopelniacz: "Opolu",
@@ -324,6 +341,7 @@ export const dolnySlaskCities: CityData[] = [
heatPumpTeaser: "Interesuje Cię pompa ciepła w Opolu? Realizujemy instalacje powietrze-woda z pomocą w uzyskaniu dofinansowania z programu Czyste Powietrze. Skontaktuj się z nami — dobierzemy optymalne rozwiązanie dla Twojego budynku.",
},
{
przyimek: "w",
slug: "klodzko",
name: "Kłodzko",
nameDopelniacz: "Kłodzku",
+63 -23
View File
@@ -10,39 +10,63 @@ export interface PricingItem {
export const pricingData: PricingItem[] = [
{
id: 'montaz-split-podstawowy',
name: 'Montaż klimatyzacji typu SPLIT (do 3.5 kW)',
priceNet: 1200,
priceGrossPrivate: 1296,
priceGrossCompany: 1476,
name: 'Montaż klimatyzatora split — podstawowy (do 4,5 kW)',
priceNet: 1400,
priceGrossPrivate: 1512,
priceGrossCompany: 1722,
category: 'split',
},
{
id: 'montaz-split-rozszerzony',
name: 'Montaż klimatyzacji typu SPLIT (powyżej 3.5 kW)',
priceNet: 1500,
priceGrossPrivate: 1620,
priceGrossCompany: 1845,
id: 'montaz-split-istniejaca',
name: 'Montaż klimatyzatora split przy istniejącej instalacji',
priceNet: 800,
priceGrossPrivate: 864,
priceGrossCompany: 984,
category: 'split',
},
{
id: 'montaz-multisplit-2',
name: 'Montaż klimatyzacji MULTISPLIT (2 jednostki wew.)',
priceNet: 2200,
priceGrossPrivate: 2376,
priceGrossCompany: 2706,
name: 'Montaż multisplit 2+1 — podstawowy (do 6 m instalacji)',
priceNet: 2400,
priceGrossPrivate: 2592,
priceGrossCompany: 2952,
category: 'multisplit',
},
{
id: 'montaz-multisplit-3',
name: 'Montaż klimatyzacji MULTISPLIT (3 jednostki wew.)',
priceNet: 3000,
priceGrossPrivate: 3240,
priceGrossCompany: 3690,
name: 'Montaż multisplit 3+1 — podstawowy (do 9 m instalacji)',
priceNet: 3200,
priceGrossPrivate: 3456,
priceGrossCompany: 3936,
category: 'multisplit',
},
{
id: 'dodatkowy-metr',
name: 'Dodatkowy metr instalacji chłodniczej',
id: 'montaz-multisplit-4',
name: 'Montaż multisplit 4+1 — podstawowy (do 12 m instalacji)',
priceNet: 3800,
priceGrossPrivate: 4104,
priceGrossCompany: 4674,
category: 'multisplit',
},
{
id: 'dodatkowy-metr-korytko',
name: 'Dodatkowy metr instalacji freonowej — korytko PCV',
priceNet: 80,
priceGrossPrivate: 86,
priceGrossCompany: 98,
category: 'additional',
},
{
id: 'dodatkowy-metr-bruzda',
name: 'Dodatkowy metr instalacji freonowej — bruzda w ścianie',
priceNet: 90,
priceGrossPrivate: 97,
priceGrossCompany: 111,
category: 'additional',
},
{
id: 'przewiert',
name: 'Dopłata za przewiert otworu instalacyjnego w betonie',
priceNet: 100,
priceGrossPrivate: 108,
priceGrossCompany: 123,
@@ -50,18 +74,34 @@ export const pricingData: PricingItem[] = [
},
{
id: 'kucie-bruzdy',
name: 'Kucie bruzdy w betonie/żelbecie (mb)',
name: 'Dopłata za kucie bruzdy instalacyjnej w żelbecie',
priceNet: 150,
priceGrossPrivate: 162,
priceGrossCompany: 184.5,
priceGrossCompany: 184,
category: 'additional',
},
{
id: 'pompa-skroplin',
name: 'Instalacja pompy skroplin',
priceNet: 400,
priceGrossPrivate: 432,
priceGrossCompany: 492,
category: 'additional',
},
{
id: 'demontaz',
name: 'Demontaż klimatyzacji',
priceNet: 300,
priceGrossPrivate: 324,
priceGrossCompany: 369,
category: 'additional',
},
{
id: 'przeglad-klimatyzacji',
name: 'Okresowy przegląd i odgrzybianie klimatyzacji',
name: 'Czyszczenie i odgrzybianie klimatyzatora',
priceNet: 250,
priceGrossPrivate: 270,
priceGrossCompany: 307.5,
priceGrossCompany: 307,
category: 'additional',
},
];
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB