Modal usług doddatkowych podział na komponenty
This commit is contained in:
8
src/lib/money.js
Normal file
8
src/lib/money.js
Normal file
@@ -0,0 +1,8 @@
|
||||
export function money(amount) {
|
||||
const n = Number(amount || 0);
|
||||
return n.toFixed(2).replace(".", ",");
|
||||
}
|
||||
|
||||
export function moneyWithLabel(v, cenaOpis) {
|
||||
return `${money(v)} ${cenaOpis}`;
|
||||
}
|
||||
47
src/lib/offer-normalize.js
Normal file
47
src/lib/offer-normalize.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/** telefon z YAML (phone/cards.yaml -> cards[]) => { id, name, price_monthly, features[] } */
|
||||
export function mapPhoneYamlToPlans(phoneCards) {
|
||||
const list = Array.isArray(phoneCards) ? phoneCards : [];
|
||||
return list
|
||||
.filter((c) => c?.widoczny !== false)
|
||||
.map((c, idx) => ({
|
||||
id: String(c?.id ?? c?.nazwa ?? idx),
|
||||
name: c?.nazwa ?? "—",
|
||||
price_monthly: Number(c?.cena?.wartosc ?? 0),
|
||||
features: (Array.isArray(c?.parametry) ? c.parametry : []).map((p) => ({
|
||||
label: p.label,
|
||||
value: p.value,
|
||||
})),
|
||||
}));
|
||||
}
|
||||
|
||||
/** dekodery z YAML */
|
||||
export function normalizeDecoders(list) {
|
||||
const arr = Array.isArray(list) ? list : [];
|
||||
return arr
|
||||
.filter((d) => d?.id && d?.nazwa)
|
||||
.map((d) => ({
|
||||
id: String(d.id),
|
||||
nazwa: String(d.nazwa),
|
||||
opis: d.opis ? String(d.opis) : "",
|
||||
cena: Number(d.cena ?? 0),
|
||||
}));
|
||||
}
|
||||
|
||||
/** dodatki z YAML (tv-addons.yaml / addons.yaml) */
|
||||
export function normalizeAddons(addons) {
|
||||
const list = Array.isArray(addons) ? addons : [];
|
||||
return list
|
||||
.filter((a) => a?.id && a?.nazwa)
|
||||
.map((a) => ({
|
||||
id: String(a.id),
|
||||
nazwa: String(a.nazwa),
|
||||
typ: String(a.typ ?? a.type ?? "checkbox"),
|
||||
ilosc: !!a.ilosc,
|
||||
min: a.min != null ? Number(a.min) : 0,
|
||||
max: a.max != null ? Number(a.max) : 10,
|
||||
krok: a.krok != null ? Number(a.krok) : 1,
|
||||
opis: a.opis ? String(a.opis) : "",
|
||||
cena: a.cena ?? 0,
|
||||
tid: a.tid != null ? String(a.tid) : "",
|
||||
}));
|
||||
}
|
||||
57
src/lib/offer-payload.js
Normal file
57
src/lib/offer-payload.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { moneyWithLabel } from "./money.js";
|
||||
|
||||
export const LS_KEY = "fuz_offer_config_v1";
|
||||
|
||||
export function buildOfferMessage(payload, cenaOpis) {
|
||||
const m = (v) => moneyWithLabel(v, cenaOpis);
|
||||
const lines = [];
|
||||
|
||||
lines.push(`Wybrana oferta: ${payload?.pkg?.name || "—"}`);
|
||||
lines.push("");
|
||||
|
||||
const t = payload?.totals || {};
|
||||
lines.push(`Pakiet: ${m(t.base ?? 0)}`);
|
||||
lines.push(`Telefon: ${payload?.phone ? m(t.phone ?? 0) : "—"}`);
|
||||
|
||||
if ("decoder" in t) lines.push(`Dekoder: ${payload?.decoder ? m(t.decoder ?? 0) : "—"}`);
|
||||
if ("tv" in t) lines.push(`Dodatki TV: ${payload?.tvAddons?.length ? m(t.tv ?? 0) : "—"}`);
|
||||
|
||||
lines.push(`Dodatkowe usługi: ${payload?.addons?.length ? m(t.addons ?? 0) : "—"}`);
|
||||
lines.push(`Łącznie: ${m(t.total ?? 0)}`);
|
||||
|
||||
if (payload?.phone) {
|
||||
lines.push("");
|
||||
lines.push(`Telefon: ${payload.phone.name} (${m(payload.phone.price)})`);
|
||||
}
|
||||
|
||||
if (payload?.decoder) {
|
||||
lines.push("");
|
||||
lines.push(`Dekoder: ${payload.decoder.name} (${m(payload.decoder.price)})`);
|
||||
}
|
||||
|
||||
if (Array.isArray(payload?.tvAddons) && payload.tvAddons.length) {
|
||||
lines.push("");
|
||||
lines.push("Pakiety dodatkowe TV:");
|
||||
for (const it of payload.tvAddons) {
|
||||
const termTxt = it.term ? `, ${it.term}` : "";
|
||||
lines.push(`- ${it.nazwa} x${it.qty}${termTxt} @ ${m(it.unit)}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(payload?.addons) && payload.addons.length) {
|
||||
lines.push("");
|
||||
lines.push("Dodatkowe usługi:");
|
||||
for (const it of payload.addons) {
|
||||
lines.push(`- ${it.nazwa} x${it.qty} @ ${m(it.unit)}`);
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
export function saveOfferToLocalStorage(payload, cenaOpis) {
|
||||
try {
|
||||
payload.message = buildOfferMessage(payload, cenaOpis);
|
||||
localStorage.setItem(LS_KEY, JSON.stringify(payload));
|
||||
} catch {}
|
||||
}
|
||||
83
src/lib/offer-pricing.js
Normal file
83
src/lib/offer-pricing.js
Normal file
@@ -0,0 +1,83 @@
|
||||
function normKey(s) {
|
||||
return String(s || "").trim().toLowerCase().replace(/\s+/g, " ");
|
||||
}
|
||||
|
||||
/** TV: wybór wariantu ceny po pkg.name, albo fallback "*" */
|
||||
export function pickTvVariant(addon, pkgName) {
|
||||
const c = addon?.cena;
|
||||
if (!Array.isArray(c)) return null;
|
||||
|
||||
const wanted = normKey(pkgName);
|
||||
|
||||
for (const row of c) {
|
||||
const pk = row?.pakiety;
|
||||
if (!Array.isArray(pk)) continue;
|
||||
if (pk.some((p) => normKey(p) === wanted)) return row;
|
||||
}
|
||||
|
||||
for (const row of c) {
|
||||
const pk = row?.pakiety;
|
||||
if (!Array.isArray(pk)) continue;
|
||||
if (pk.some((p) => String(p).trim() === "*")) return row;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function isTvAddonAvailableForPkg(addon, pkg) {
|
||||
if (!pkg) return false;
|
||||
const v = pickTvVariant(addon, String(pkg?.name ?? ""));
|
||||
return !!v;
|
||||
}
|
||||
|
||||
export function hasTvTermPricing(addon, pkg) {
|
||||
const c = addon?.cena;
|
||||
if (!Array.isArray(c)) return false;
|
||||
|
||||
const v = pickTvVariant(addon, String(pkg?.name ?? ""));
|
||||
if (!v || typeof v !== "object") return false;
|
||||
|
||||
return v["12m"] != null && v.bezterminowo != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ cena jednostkowa:
|
||||
* - addons.yaml: number / string / legacy {default, by_name}
|
||||
* - tv-addons.yaml: tablica wariantów
|
||||
*/
|
||||
export function getAddonUnitPrice(addon, pkg, term /* "12m"|"bezterminowo"|null */) {
|
||||
const c = addon?.cena;
|
||||
|
||||
if (typeof c === "number") return c;
|
||||
if (typeof c === "string" && c.trim() !== "" && !Number.isNaN(Number(c))) return Number(c);
|
||||
|
||||
// tv-addons.yaml
|
||||
if (Array.isArray(c)) {
|
||||
const v = pickTvVariant(addon, String(pkg?.name ?? ""));
|
||||
if (!v) return 0;
|
||||
|
||||
const t = term || "12m";
|
||||
if (v[t] != null) return Number(v[t]) || 0;
|
||||
|
||||
if (v.bezterminowo != null) return Number(v.bezterminowo) || 0;
|
||||
if (v["12m"] != null) return Number(v["12m"]) || 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// legacy object
|
||||
if (c && typeof c === "object") {
|
||||
const name = String(pkg?.name ?? "");
|
||||
const wanted = normKey(name);
|
||||
|
||||
const byName = c.by_name || c.byName || c.by_nazwa || c.byNazwa;
|
||||
if (byName && typeof byName === "object" && name) {
|
||||
for (const k of Object.keys(byName)) {
|
||||
if (normKey(k) === wanted) return Number(byName[k]) || 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (c.default != null) return Number(c.default) || 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user