Porządkowanie kodu, dodanie sekcji wyszukiwania kanałów

This commit is contained in:
dm
2025-12-12 19:48:53 +01:00
parent bf67147cf5
commit 5822237745
47 changed files with 17203 additions and 15686 deletions

View File

@@ -0,0 +1,167 @@
//InternetCards.jsx
import { useEffect, useState } from "preact/hooks";
import InternetAddonsModal from "./InternetAddonsModal.jsx";
import "../../styles/offers/offers-table.css";
export default function InternetDbOffersCards({
}) {
const [selected, setSelected] = useState({});
const [labels, setLabels] = useState({});
const [plans, setPlans] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const [addonsModalOpen, setAddonsModalOpen] = useState(false);
const [activePlan, setActivePlan] = useState(null);
useEffect(() => {
if (typeof window !== "undefined" && window.fuzSwitchState) {
const { selected: sel, labels: labs } = window.fuzSwitchState;
if (sel) setSelected(sel);
if (labs) setLabels(labs);
}
function handler(e) {
const detail = e.detail || {};
if (detail.selected) {
setSelected(detail.selected);
}
if (detail.labels) {
setLabels(detail.labels);
}
}
window.addEventListener("fuz:switch-change", handler);
return () => window.removeEventListener("fuz:switch-change", handler);
}, []);
const buildingCode = Number(selected.budynek) || 1;
const contractCode = Number(selected.umowa) || 1;
useEffect(() => {
if (!buildingCode || !contractCode) return;
let cancelled = false;
async function load() {
setLoading(true);
setError("");
try {
const params = new URLSearchParams({
building: String(buildingCode),
contract: String(contractCode),
});
const res = await fetch(`/api/internet/plans?${params.toString()}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
if (!cancelled) {
setPlans(Array.isArray(json.data) ? json.data : []);
}
} catch (err) {
console.error("Błąd pobierania planów internetu:", err);
if (!cancelled) setError("Nie udało się załadować ofert.");
} finally {
if (!cancelled) setLoading(false);
}
}
load();
return () => {
cancelled = true;
};
}, [buildingCode, contractCode]);
const contractLabel = labels.umowa || "";
return (
<section class="f-offers">
{loading && <p>Ładowanie ofert...</p>}
{error && <p class="text-red-600">{error}</p>}
{!loading && !error && (
<div class={`f-offers-grid f-count-${plans.length || 1}`}>
{plans.map((plan) => (
<OfferCard
key={plan.id}
plan={plan}
contractLabel={contractLabel}
onConfigureAddons={() => {
setActivePlan(plan);
setAddonsModalOpen(true);
}}
/>
))}
</div>
)}
<InternetAddonsModal
isOpen={addonsModalOpen}
onClose={() => setAddonsModalOpen(false)}
plan={activePlan}
/>
</section>
);
}
function OfferCard({ plan, contractLabel, onConfigureAddons }) {
const basePrice = plan.price_monthly;
const installPrice = plan.price_installation;
const featureRows = plan.features || [];
const effectiveContract = contractLabel || "—";
return (
<div class={`f-card ${plan.popular ? "f-card-popular" : ""}`}>
<div class="f-card-header">
<div class="f-card-name">{plan.name}</div>
<div class="f-card-price">
{basePrice != null ? `${basePrice} zł/mies.` : "—"}
</div>
</div>
<ul class="f-card-features">
{featureRows.map((f) => {
let val = f.value;
let display;
if (val === true || val === "true") display = "✓";
else if (val === false || val === "false" || val == null) display = "✕";
else display = val;
return (
<li class="f-card-row">
<span class="f-card-label">{f.label}</span>
<span class="f-card-value">{display}</span>
</li>
);
})}
<li class="f-card-row">
<span class="f-card-label">Umowa</span>
<span class="f-card-value">{effectiveContract}</span>
</li>
<li class="f-card-row">
<span class="f-card-label">Aktywacja</span>
<span class="f-card-value">
{installPrice != null ? `${installPrice}` : "—"}
</span>
</li>
</ul>
<button
type="button"
class="btn btn-primary mt-4"
onClick={onConfigureAddons}
>
Skonfiguruj usługi dodatkowe
</button>
</div>
);
}