import { useEffect, useMemo, useState } from "preact/hooks"; import OfferModalShell from "../modals/OfferModalShell.jsx"; import PlanSection from "../modals/sections/PlanSection.jsx"; import DecoderSection from "../modals/sections/DecoderSection.jsx"; import TvAddonsSection from "../modals/sections/TvAddonsSection.jsx"; import PhoneSection from "../modals/sections/PhoneSection.jsx"; import AddonsSection from "../modals/sections/AddonsSection.jsx"; import SummarySection from "../modals/sections/SummarySection.jsx"; import FloatingTotal from "../modals/sections/FloatingTotal.jsx"; import { mapPhoneYamlToPlans, normalizeAddons, normalizeDecoders } from "../../lib/offer-normalize.js"; import { isTvAddonAvailableForPkg, hasTvTermPricing, getAddonUnitPrice } from "../../lib/offer-pricing.js"; import { saveOfferToLocalStorage } from "../../lib/offer-payload.js"; import "../../styles/modal.css"; import "../../styles/addons.css"; export default function JamboxAddonsModal({ isOpen, onClose, pkg, phoneCards = [], tvAddons = [], addons = [], decoders = [], cenaOpis = "zł/mies.", }) { const phonePlans = useMemo(() => mapPhoneYamlToPlans(phoneCards), [phoneCards]); const tvAddonsList = useMemo(() => normalizeAddons(tvAddons), [tvAddons]); const addonsList = useMemo(() => normalizeAddons(addons), [addons]); const decodersList = useMemo(() => normalizeDecoders(decoders), [decoders]); const tvAddonsVisible = useMemo(() => { if (!pkg) return []; return tvAddonsList.filter((a) => isTvAddonAvailableForPkg(a, pkg)); }, [tvAddonsList, pkg]); const [selectedPhoneId, setSelectedPhoneId] = useState(null); const [selectedDecoderId, setSelectedDecoderId] = useState(null); const [selectedQty, setSelectedQty] = useState({}); const [tvTerm, setTvTerm] = useState({}); // { [id]: "12m" | "bezterminowo" } const [openSections, setOpenSections] = useState({ base: true, decoder: false, tv: false, phone: false, addons: false, summary: false, }); const toggleSection = (key) => { setOpenSections((prev) => { const nextOpen = !prev[key]; return { base: false, decoder: false, tv: false, phone: false, addons: false, summary: false, [key]: nextOpen, }; }); }; useEffect(() => { if (!isOpen) return; setSelectedPhoneId(null); setSelectedQty({}); setTvTerm({}); const d0 = (Array.isArray(decodersList) && decodersList.find((d) => Number(d.cena) === 0)) || (Array.isArray(decodersList) ? decodersList[0] : null); setSelectedDecoderId(d0 ? String(d0.id) : null); setOpenSections({ base: true, decoder: false, tv: false, phone: false, addons: false, summary: false, }); }, [isOpen, pkg?.id, decodersList]); if (!isOpen || !pkg) return null; const basePrice = Number(pkg.price_monthly || 0); const phonePrice = useMemo(() => { if (!selectedPhoneId) return 0; const p = phonePlans.find((x) => String(x.id) === String(selectedPhoneId)); return Number(p?.price_monthly || 0); }, [selectedPhoneId, phonePlans]); const decoderPrice = useMemo(() => { if (!selectedDecoderId) return 0; const d = decodersList.find((x) => String(x.id) === String(selectedDecoderId)); return Number(d?.cena || 0); }, [selectedDecoderId, decodersList]); const tvAddonsPrice = useMemo(() => { return tvAddonsVisible.reduce((sum, a) => { const qty = Number(selectedQty[a.id] || 0); if (qty <= 0) return sum; const termPricing = hasTvTermPricing(a, pkg); const term = tvTerm[a.id] || "12m"; const unit = getAddonUnitPrice(a, pkg, termPricing ? term : null); return sum + qty * unit; }, 0); }, [selectedQty, tvAddonsVisible, tvTerm, pkg]); const addonsOnlyPrice = useMemo(() => { return addonsList.reduce((sum, a) => { const qty = Number(selectedQty[a.id] || 0); const unit = getAddonUnitPrice(a, pkg, null); return sum + qty * unit; }, 0); }, [selectedQty, addonsList, pkg]); const totalMonthly = basePrice + phonePrice + decoderPrice + tvAddonsPrice + addonsOnlyPrice; function buildOfferPayload() { const phone = selectedPhoneId ? phonePlans.find((p) => String(p.id) === String(selectedPhoneId)) : null; const decoder = selectedDecoderId ? decodersList.find((d) => String(d.id) === String(selectedDecoderId)) : null; const tvChosen = tvAddonsVisible .map((a) => { const qty = Number(selectedQty[a.id] || 0); if (qty <= 0) return null; const termPricing = hasTvTermPricing(a, pkg); const term = tvTerm[a.id] || "12m"; const unit = getAddonUnitPrice(a, pkg, termPricing ? term : null); return { id: a.id, nazwa: a.nazwa, qty, term: termPricing ? term : null, unit, }; }) .filter(Boolean); const addonsChosen = addonsList .map((a) => { const qty = Number(selectedQty[a.id] || 0); if (qty <= 0) return null; const unit = getAddonUnitPrice(a, pkg, null); return { id: a.id, nazwa: a.nazwa, qty, unit }; }) .filter(Boolean); return { createdAt: new Date().toISOString(), pkg: { id: pkg?.id ?? null, name: pkg?.name ?? "", price: basePrice }, phone: phone ? { id: phone.id, name: phone.name, price: phone.price_monthly } : null, decoder: decoder ? { id: decoder.id, name: decoder.nazwa, price: decoder.cena } : null, tvAddons: tvChosen, addons: addonsChosen, totals: { base: basePrice, phone: phonePrice, decoder: decoderPrice, tv: tvAddonsPrice, addons: addonsOnlyPrice, total: totalMonthly, currencyLabel: cenaOpis, }, }; } const onSend = () => { const payload = buildOfferPayload(); saveOfferToLocalStorage(payload, cenaOpis); }; return ( toggleSection("base")} price={basePrice} cenaOpis={cenaOpis} features={pkg.features || []} /> toggleSection("decoder")} cenaOpis={cenaOpis} decoders={decodersList} selectedDecoderId={selectedDecoderId} setSelectedDecoderId={setSelectedDecoderId} decoderPrice={decoderPrice} /> toggleSection("tv")} cenaOpis={cenaOpis} pkg={pkg} tvAddonsVisible={tvAddonsVisible} selectedQty={selectedQty} setSelectedQty={setSelectedQty} tvTerm={tvTerm} setTvTerm={setTvTerm} tvAddonsPrice={tvAddonsPrice} /> toggleSection("phone")} cenaOpis={cenaOpis} phonePlans={phonePlans} selectedPhoneId={selectedPhoneId} setSelectedPhoneId={setSelectedPhoneId} phonePrice={phonePrice} /> toggleSection("addons")} cenaOpis={cenaOpis} addonsList={addonsList} selectedQty={selectedQty} setSelectedQty={setSelectedQty} addonsPrice={addonsOnlyPrice} getUnitPrice={(a) => getAddonUnitPrice(a, pkg, null)} /> toggleSection("summary")} cenaOpis={cenaOpis} totalMonthly={totalMonthly} ctaHref="/kontakt" onSend={onSend} rows={[ { label: "Pakiet", value: basePrice, showDashIfZero: false }, { label: "Telefon", value: phonePrice, showDashIfZero: true }, { label: "Dekoder", value: decoderPrice, showDashIfZero: true }, { label: "Pakiety premium", value: tvAddonsPrice, showDashIfZero: true }, { label: "Dodatkowe usługi", value: addonsOnlyPrice, showDashIfZero: true }, ]} /> ); }