diff --git a/src/data/ServicesRange.db b/src/data/ServicesRange.db index 9310e44..d187eb1 100644 Binary files a/src/data/ServicesRange.db and b/src/data/ServicesRange.db differ diff --git a/src/islands/Internet/InternetAddonsModal.jsx b/src/islands/Internet/InternetAddonsModal.jsx new file mode 100644 index 0000000..7f52216 --- /dev/null +++ b/src/islands/Internet/InternetAddonsModal.jsx @@ -0,0 +1,365 @@ +import { useEffect, useState } from "preact/hooks"; +import "../../styles/modal.css"; +import "../../styles/offers/offers-table.css"; + +export default function InternetAddonsModal({ isOpen, onClose, plan }) { + const [phonePlans, setPhonePlans] = useState([]); + const [addons, setAddons] = useState([]); + + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + + const [selectedPhoneId, setSelectedPhoneId] = useState(null); + const [selectedAddons, setSelectedAddons] = useState([]); + + // który pakiet telefoniczny jest rozwinięty + const [openPhoneId, setOpenPhoneId] = useState(null); + + // czy akordeon internetu (fiber) jest rozwinięty + const [baseOpen, setBaseOpen] = useState(true); + + // reset wyborów po otwarciu nowego planu + useEffect(() => { + if (!isOpen) return; + setSelectedPhoneId(null); + setSelectedAddons([]); + setOpenPhoneId(null); + setBaseOpen(true); + }, [isOpen, plan]); + + // ładowanie danych + useEffect(() => { + if (!isOpen) return; + + let cancelled = false; + + async function loadData() { + setLoading(true); + setError(""); + + try { + // telefon + const phoneRes = await fetch("/api/phone/plans"); + if (!phoneRes.ok) throw new Error(`HTTP ${phoneRes.status} (phone)`); + + const phoneJson = await phoneRes.json(); + const phoneData = Array.isArray(phoneJson.data) ? phoneJson.data : []; + + // dodatki + const addonsRes = await fetch("/api/internet/addons"); + if (!addonsRes.ok) throw new Error(`HTTP ${addonsRes.status} (addons)`); + + const addonsJson = await addonsRes.json(); + const addonsData = Array.isArray(addonsJson.data) ? addonsJson.data : []; + + if (!cancelled) { + setPhonePlans(phoneData); + setAddons(addonsData); + } + } catch (err) { + console.error("❌ Błąd ładowania danych do InternetAddonsModal:", err); + if (!cancelled) { + setError("Nie udało się załadować danych dodatkowych usług."); + } + } finally { + if (!cancelled) setLoading(false); + } + } + + loadData(); + return () => { + cancelled = true; + }; + }, [isOpen]); + + if (!isOpen || !plan) return null; + + const basePrice = plan.price_monthly || 0; + + const phonePrice = (() => { + if (!selectedPhoneId) return 0; + const p = phonePlans.find((p) => p.id === selectedPhoneId); + return p?.price_monthly || 0; + })(); + + const addonsPrice = selectedAddons.reduce((sum, sel) => { + const addon = addons.find((a) => a.id === sel.addonId); + if (!addon) return sum; + const opt = addon.options.find((o) => o.id === sel.optionId); + if (!opt) return sum; + return sum + (opt.price || 0); + }, 0); + + const totalMonthly = basePrice + phonePrice + addonsPrice; + + const handleAddonToggle = (addonId, optionId) => { + setSelectedAddons((prev) => { + const exists = prev.some( + (x) => x.addonId === addonId && x.optionId === optionId + ); + if (exists) { + return prev.filter( + (x) => !(x.addonId === addonId && x.optionId === optionId) + ); + } else { + return [...prev, { addonId, optionId }]; + } + }); + }; + + const togglePhoneOpen = (id) => { + setOpenPhoneId((prev) => (prev === id ? null : id)); + }; + + return ( +
+ ); +} diff --git a/src/islands/OffersInternetCards.jsx b/src/islands/Internet/OffersInternetCards.jsx similarity index 69% rename from src/islands/OffersInternetCards.jsx rename to src/islands/Internet/OffersInternetCards.jsx index ea1ba71..13bd8ea 100644 --- a/src/islands/OffersInternetCards.jsx +++ b/src/islands/Internet/OffersInternetCards.jsx @@ -1,15 +1,20 @@ import { useEffect, useState } from "preact/hooks"; -import "../styles/offers/offers-table.css"; +import "../../styles/offers/offers-table.css"; +import InternetAddonsModal from "./InternetAddonsModal.jsx"; // 🔹 dostosuj ścieżkę, jeśli inna export default function InternetDbOffersCards({ title = "Oferty Internetu FUZ", }) { const [selected, setSelected] = useState({}); - const [labels, setLabels] = useState({}); + const [labels, setLabels] = useState({}); const [plans, setPlans] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); + // 🔹 stan modala z dodatkami + const [addonsModalOpen, setAddonsModalOpen] = useState(false); + const [activePlan, setActivePlan] = useState(null); + // nasłuchuj globalnego eventu z OffersSwitches useEffect(() => { function handler(e) { @@ -18,7 +23,7 @@ export default function InternetDbOffersCards({ setSelected(detail.selected); } if (detail.labels) { - setLabels(detail.labels); + setLabels(detail.labels); } } @@ -65,10 +70,11 @@ export default function InternetDbOffersCards({ }; }, [buildingCode, contractCode]); - const contractLabel = labels.umowa || ""; + const contractLabel = labels.umowa || ""; return (Ładowanie ofert...
} {error &&{error}
} @@ -79,26 +85,45 @@ export default function InternetDbOffersCards({ key={plan.id} plan={plan} contractLabel={contractLabel} + onConfigureAddons={() => { + setActivePlan(plan); + setAddonsModalOpen(true); + }} /> ))} )} + + {/* 🔹 Modal z usługami dodatkowymi (internet + telefon + addon’y) */} +