Modal usług doddatkowych podział na komponenty
This commit is contained in:
163
src/islands/modals/sections/TvAddonsSection.jsx
Normal file
163
src/islands/modals/sections/TvAddonsSection.jsx
Normal file
@@ -0,0 +1,163 @@
|
||||
import SectionAccordion from "./SectionAccordion.jsx";
|
||||
import { money } from "../../../lib/money.js";
|
||||
import { hasTvTermPricing, getAddonUnitPrice } from "../../../lib/offer-pricing.js";
|
||||
|
||||
export default function TvAddonsSection({
|
||||
open,
|
||||
onToggle,
|
||||
cenaOpis,
|
||||
pkg,
|
||||
tvAddonsVisible = [],
|
||||
selectedQty,
|
||||
setSelectedQty,
|
||||
tvTerm,
|
||||
setTvTerm,
|
||||
tvAddonsPrice,
|
||||
}) {
|
||||
const toggleCheckboxAddon = (id) => {
|
||||
setSelectedQty((prev) => {
|
||||
const next = { ...prev };
|
||||
next[id] = (next[id] || 0) > 0 ? 0 : 1;
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
const setQtyAddon = (id, qty, min, max) => {
|
||||
const safe = Math.max(min, Math.min(max, qty));
|
||||
setSelectedQty((prev) => ({ ...prev, [id]: safe }));
|
||||
};
|
||||
|
||||
const renderRow = (a) => {
|
||||
const qty = Number(selectedQty[a.id] || 0);
|
||||
const isQty = a.typ === "quantity" || a.ilosc === true;
|
||||
|
||||
const termPricing = hasTvTermPricing(a, pkg);
|
||||
const term = tvTerm[a.id] || "12m";
|
||||
const unit = getAddonUnitPrice(a, pkg, termPricing ? term : null);
|
||||
|
||||
if (!isQty) {
|
||||
return (
|
||||
<label class="f-addon-item f-addon-item--tv" key={"tv-" + a.id}>
|
||||
<div class="f-addon-checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={qty > 0}
|
||||
onChange={() => toggleCheckboxAddon(a.id)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="f-addon-main">
|
||||
<div class="f-addon-name">{a.nazwa}</div>
|
||||
|
||||
{termPricing && (
|
||||
<div class="mt-2 flex flex-wrap gap-3 text-sm" onClick={(e) => e.stopPropagation()}>
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<input
|
||||
type="radio"
|
||||
name={`term-${a.id}`}
|
||||
checked={(tvTerm[a.id] || "12m") === "12m"}
|
||||
onChange={() => setTvTerm((p) => ({ ...p, [a.id]: "12m" }))}
|
||||
/>
|
||||
<span>12 miesięcy</span>
|
||||
</label>
|
||||
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<input
|
||||
type="radio"
|
||||
name={`term-${a.id}`}
|
||||
checked={(tvTerm[a.id] || "12m") === "bezterminowo"}
|
||||
onChange={() => setTvTerm((p) => ({ ...p, [a.id]: "bezterminowo" }))}
|
||||
/>
|
||||
<span>Bezterminowo</span>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="f-addon-price">{money(unit)} {cenaOpis}</div>
|
||||
|
||||
{/* ✅ osobny wiersz na pełną szerokość */}
|
||||
{(a.tid || a.opis) && (
|
||||
<div class="f-addon-below" onClick={(e) => e.stopPropagation()}>
|
||||
{a.tid ? (
|
||||
<a
|
||||
class="f-addon-more"
|
||||
href={`/internet-telewizja/pakiety-tematyczne#tid-${encodeURIComponent(a.tid)}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label={`Więcej informacji o pakiecie ${a.nazwa ?? ""} (otwiera się w nowej karcie)`}
|
||||
title={`Więcej o pakiecie ${a.nazwa ?? ""}`}
|
||||
>
|
||||
Przejdź do szczegółowych informacji pakietu {a.nazwa ?? ""}
|
||||
</a>
|
||||
) : (
|
||||
a.opis ? <div class="f-addon-desc">{a.opis}</div> : null
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</label>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
const min = Number.isFinite(a.min) ? a.min : 0;
|
||||
const max = Number.isFinite(a.max) ? a.max : 10;
|
||||
const step = Number.isFinite(a.krok) ? a.krok : 1;
|
||||
const lineTotal = qty * unit;
|
||||
|
||||
return (
|
||||
<div class="f-addon-item f-addon-item--qty f-addon-item--tv" key={"tvq-" + a.id}>
|
||||
<div class="f-addon-checkbox" aria-hidden="true"></div>
|
||||
|
||||
<div class="f-addon-main">
|
||||
<div class="f-addon-name">{a.nazwa}</div>
|
||||
{a.opis && <div class="f-addon-desc">{a.opis}</div>}
|
||||
</div>
|
||||
|
||||
<div class="f-addon-qty" onClick={(e) => e.stopPropagation()}>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline"
|
||||
onClick={() => setQtyAddon(a.id, qty - step, min, max)}
|
||||
disabled={qty <= min}
|
||||
>
|
||||
−
|
||||
</button>
|
||||
|
||||
<span class="f-addon-qty-value">{qty}</span>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline"
|
||||
onClick={() => setQtyAddon(a.id, qty + step, min, max)}
|
||||
disabled={qty >= max}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="f-addon-price">
|
||||
<div>{money(unit)} {cenaOpis}</div>
|
||||
<div class="f-addon-price-total">{qty > 0 ? `${money(lineTotal)} ${cenaOpis}` : "—"}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="f-modal-section">
|
||||
<SectionAccordion
|
||||
title="Pakiety dodatkowe TV"
|
||||
right={<span class="f-modal-phone-price">{tvAddonsPrice ? `${money(tvAddonsPrice)} ${cenaOpis}` : "—"}</span>}
|
||||
open={open}
|
||||
onToggle={onToggle}
|
||||
>
|
||||
{tvAddonsVisible.length === 0 ? (
|
||||
<p>Brak pakietów dodatkowych TV.</p>
|
||||
) : (
|
||||
<div class="f-addon-list">{tvAddonsVisible.map(renderRow)}</div>
|
||||
)}
|
||||
</SectionAccordion>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user