Formatowanie cen
This commit is contained in:
@@ -3,8 +3,6 @@ opis: |
|
|||||||
Wybierz rodzaj budynku i czas trwania umowy
|
Wybierz rodzaj budynku i czas trwania umowy
|
||||||
cena_opis: "zł/mies."
|
cena_opis: "zł/mies."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
grupy:
|
grupy:
|
||||||
- id: "EVIO"
|
- id: "EVIO"
|
||||||
nazwa: "Evio"
|
nazwa: "Evio"
|
||||||
|
|||||||
@@ -16,7 +16,12 @@ grupy:
|
|||||||
canal_plus:
|
canal_plus:
|
||||||
tytul: CANAL+
|
tytul: CANAL+
|
||||||
rejestracja:
|
rejestracja:
|
||||||
opis: Aby skorzystać z Platformy należy się zarejestrować
|
opis: |
|
||||||
|
Platforma CANAL+ jest dostępna za pośrednictwem strony internetowej, podłączonych telewizorów, aplikacji na smartfony i tablety, konsol do gier i urządzeń takich jak Apple TV i Google Chromecast.
|
||||||
|
Wszystkie obsługiwane urządzenia opisane są na stronie: canalplus.com
|
||||||
|
|
||||||
|
Aby skorzystać z Platformy należy się zarejestrować
|
||||||
|
|
||||||
label: Rejestracja CANAL+
|
label: Rejestracja CANAL+
|
||||||
href: "https://jambox.pl/cplus-rejestracja"
|
href: "https://jambox.pl/cplus-rejestracja"
|
||||||
title: "Rejestracja w usłudze streamingowej"
|
title: "Rejestracja w usłudze streamingowej"
|
||||||
@@ -63,9 +68,6 @@ dodatki:
|
|||||||
opis: |
|
opis: |
|
||||||
Pakiet sportowy Canal+ oraz dostęp do platformy streamingowej Canal+
|
Pakiet sportowy Canal+ oraz dostęp do platformy streamingowej Canal+
|
||||||
|
|
||||||
Platforma CANAL+ jest dostępna za pośrednictwem strony internetowej, podłączonych telewizorów, aplikacji na smartfony i tablety, konsol do gier i urządzeń takich jak Apple TV i Google Chromecast.
|
|
||||||
Wszystkie obsługiwane urządzenia opisane są na stronie: canalplus.com
|
|
||||||
|
|
||||||
cena:
|
cena:
|
||||||
- pakiety:
|
- pakiety:
|
||||||
- Smart
|
- Smart
|
||||||
|
|||||||
@@ -4,21 +4,10 @@ import OffersSwitches from "../Switches.jsx";
|
|||||||
import InternetAddonsModal from "./InternetAddonsModal.jsx";
|
import InternetAddonsModal from "./InternetAddonsModal.jsx";
|
||||||
import "../../styles/cards.css";
|
import "../../styles/cards.css";
|
||||||
|
|
||||||
function formatMoney(amount, currency = "PLN") {
|
import { moneyWithLabel, money } from "../../lib/money.js";
|
||||||
if (typeof amount !== "number" || Number.isNaN(amount)) return "";
|
|
||||||
try {
|
|
||||||
return new Intl.NumberFormat("pl-PL", {
|
|
||||||
style: "",
|
|
||||||
currency,
|
|
||||||
maximumFractionDigits: 0,
|
|
||||||
}).format(amount);
|
|
||||||
} catch {
|
|
||||||
return String(amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ✅ mapper: InternetCard(YAML) + match + labels -> plan (dla modala)
|
// ✅ mapper: InternetCard(YAML) + match + labels -> plan (dla modala)
|
||||||
function mapCardToPlan(card, match, labels, waluta) {
|
function mapCardToPlan(card, match, labels, cenaOpis) {
|
||||||
const baseParams = Array.isArray(card?.parametry) ? card.parametry : [];
|
const baseParams = Array.isArray(card?.parametry) ? card.parametry : [];
|
||||||
|
|
||||||
const features = baseParams.map((p) => ({
|
const features = baseParams.map((p) => ({
|
||||||
@@ -30,8 +19,7 @@ function mapCardToPlan(card, match, labels, waluta) {
|
|||||||
features.push({ label: "Umowa", value: labels?.umowa || "—" });
|
features.push({ label: "Umowa", value: labels?.umowa || "—" });
|
||||||
features.push({
|
features.push({
|
||||||
label: "Aktywacja",
|
label: "Aktywacja",
|
||||||
value:
|
value: typeof match?.aktywacja === "number" ? `${money(match.aktywacja)} zł` : "—",
|
||||||
typeof match?.aktywacja === "number" ? formatMoney(match.aktywacja, waluta) : "—",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -39,6 +27,7 @@ function mapCardToPlan(card, match, labels, waluta) {
|
|||||||
price_monthly: typeof match?.miesiecznie === "number" ? match.miesiecznie : 0,
|
price_monthly: typeof match?.miesiecznie === "number" ? match.miesiecznie : 0,
|
||||||
price_installation: typeof match?.aktywacja === "number" ? match.aktywacja : 0,
|
price_installation: typeof match?.aktywacja === "number" ? match.aktywacja : 0,
|
||||||
features,
|
features,
|
||||||
|
cenaOpis,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,23 +41,23 @@ function mapCardToPlan(card, match, labels, waluta) {
|
|||||||
* phoneCards?: any[],
|
* phoneCards?: any[],
|
||||||
* addons?: any[],
|
* addons?: any[],
|
||||||
* addonsCenaOpis?: string,
|
* addonsCenaOpis?: string,
|
||||||
* switches?: any[] // ✅ NOWE: przełączniki z YAML
|
* switches?: any[]
|
||||||
* }} props
|
* }} props
|
||||||
*/
|
*/
|
||||||
export default function InternetCards({
|
export default function InternetCards({
|
||||||
title = "",
|
title = "",
|
||||||
description = "",
|
description = "",
|
||||||
cards = [],
|
cards = [],
|
||||||
waluta = "PLN",
|
waluta = "PLN", // zostawiamy, bo może się przydać dalej (np. w modalu), ale tu nie jest używana
|
||||||
cenaOpis = "zł/mies.",
|
cenaOpis = "zł/mies.",
|
||||||
phoneCards = [],
|
phoneCards = [],
|
||||||
addons = [],
|
addons = [],
|
||||||
addonsCenaOpis = "zł/mies.",
|
addonsCenaOpis = "zł/mies.",
|
||||||
switches = [], // ✅ NOWE
|
switches = [],
|
||||||
}) {
|
}) {
|
||||||
const visibleCards = Array.isArray(cards) ? cards : [];
|
const visibleCards = Array.isArray(cards) ? cards : [];
|
||||||
|
|
||||||
// switch state (teraz idzie z OffersSwitches na podstawie YAML)
|
// switch state (idzie z OffersSwitches na podstawie YAML)
|
||||||
const [selected, setSelected] = useState({});
|
const [selected, setSelected] = useState({});
|
||||||
const [labels, setLabels] = useState({});
|
const [labels, setLabels] = useState({});
|
||||||
|
|
||||||
@@ -103,7 +92,6 @@ export default function InternetCards({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* ✅ TERAZ switcher dostaje dane z YAML */}
|
|
||||||
<OffersSwitches switches={switches} />
|
<OffersSwitches switches={switches} />
|
||||||
|
|
||||||
{visibleCards.length === 0 ? (
|
{visibleCards.length === 0 ? (
|
||||||
@@ -116,7 +104,6 @@ export default function InternetCards({
|
|||||||
card={card}
|
card={card}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
labels={labels}
|
labels={labels}
|
||||||
waluta={waluta}
|
|
||||||
cenaOpis={cenaOpis}
|
cenaOpis={cenaOpis}
|
||||||
onConfigureAddons={(plan) => {
|
onConfigureAddons={(plan) => {
|
||||||
setActivePlan(plan);
|
setActivePlan(plan);
|
||||||
@@ -139,7 +126,7 @@ export default function InternetCards({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function OfferCard({ card, selected, labels, waluta, cenaOpis, onConfigureAddons }) {
|
function OfferCard({ card, selected, labels, cenaOpis, onConfigureAddons }) {
|
||||||
const baseParams = Array.isArray(card?.parametry) ? card.parametry : [];
|
const baseParams = Array.isArray(card?.parametry) ? card.parametry : [];
|
||||||
const ceny = Array.isArray(card?.ceny) ? card.ceny : [];
|
const ceny = Array.isArray(card?.ceny) ? card.ceny : [];
|
||||||
|
|
||||||
@@ -160,7 +147,7 @@ function OfferCard({ card, selected, labels, waluta, cenaOpis, onConfigureAddons
|
|||||||
{
|
{
|
||||||
klucz: "aktywacja",
|
klucz: "aktywacja",
|
||||||
label: "Aktywacja",
|
label: "Aktywacja",
|
||||||
value: typeof akt === "number" ? formatMoney(akt, waluta) : "—",
|
value: typeof akt === "number" ? `${money(akt)} zł` : "—",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -175,9 +162,7 @@ function OfferCard({ card, selected, labels, waluta, cenaOpis, onConfigureAddons
|
|||||||
|
|
||||||
<div class="f-card-price">
|
<div class="f-card-price">
|
||||||
{typeof mies === "number" ? (
|
{typeof mies === "number" ? (
|
||||||
<>
|
<>{moneyWithLabel(mies, cenaOpis, false)}</>
|
||||||
{formatMoney(mies, waluta)} <span class="opacity-80">{cenaOpis}</span>
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<span class="opacity-70">Wybierz opcje</span>
|
<span class="opacity-70">Wybierz opcje</span>
|
||||||
)}
|
)}
|
||||||
@@ -198,7 +183,7 @@ function OfferCard({ card, selected, labels, waluta, cenaOpis, onConfigureAddons
|
|||||||
class="btn btn-primary mt-4"
|
class="btn btn-primary mt-4"
|
||||||
disabled={!canConfigureAddons}
|
disabled={!canConfigureAddons}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const plan = mapCardToPlan(card, match, labels, waluta);
|
const plan = mapCardToPlan(card, match, labels, cenaOpis);
|
||||||
onConfigureAddons(plan);
|
onConfigureAddons(plan);
|
||||||
}}
|
}}
|
||||||
title={!canConfigureAddons ? "Wybierz typ budynku i umowę" : ""}
|
title={!canConfigureAddons ? "Wybierz typ budynku i umowę" : ""}
|
||||||
|
|||||||
@@ -6,18 +6,7 @@ import JamboxChannelsModal from "./JamboxChannelsModal.jsx";
|
|||||||
import JamboxAddonsModal from "./JamboxAddonsModal.jsx";
|
import JamboxAddonsModal from "./JamboxAddonsModal.jsx";
|
||||||
import Markdown from "../Markdown.jsx";
|
import Markdown from "../Markdown.jsx";
|
||||||
|
|
||||||
function formatMoney(amount, currency = "PLN") {
|
import { moneyWithLabel, money } from "../../lib/money.js";
|
||||||
if (typeof amount !== "number" || Number.isNaN(amount)) return "";
|
|
||||||
try {
|
|
||||||
return new Intl.NumberFormat("pl-PL", {
|
|
||||||
style: "currency",
|
|
||||||
currency,
|
|
||||||
maximumFractionDigits: 0,
|
|
||||||
}).format(amount);
|
|
||||||
} catch {
|
|
||||||
return String(amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toFeatureRows(params) {
|
function toFeatureRows(params) {
|
||||||
const list = Array.isArray(params) ? params : [];
|
const list = Array.isArray(params) ? params : [];
|
||||||
@@ -52,7 +41,6 @@ function toFeatureRows(params) {
|
|||||||
* decoders?: Decoder[],
|
* decoders?: Decoder[],
|
||||||
* addonsCenaOpis?: string,
|
* addonsCenaOpis?: string,
|
||||||
* channels?: ChannelYaml[],
|
* channels?: ChannelYaml[],
|
||||||
* channels?: ChannelYaml[]
|
|
||||||
* }} props
|
* }} props
|
||||||
*/
|
*/
|
||||||
export default function JamboxCards({
|
export default function JamboxCards({
|
||||||
@@ -60,7 +48,7 @@ export default function JamboxCards({
|
|||||||
description = "",
|
description = "",
|
||||||
cards = [],
|
cards = [],
|
||||||
internetWspolne = [],
|
internetWspolne = [],
|
||||||
waluta = "PLN",
|
waluta = "PLN", // zostawiamy (może być potrzebne w modalach), ale tu nie jest używane do formatowania
|
||||||
cenaOpis = "zł/mies.",
|
cenaOpis = "zł/mies.",
|
||||||
|
|
||||||
phoneCards = [],
|
phoneCards = [],
|
||||||
@@ -122,7 +110,6 @@ export default function JamboxCards({
|
|||||||
wsp={wsp}
|
wsp={wsp}
|
||||||
selected={selected}
|
selected={selected}
|
||||||
labels={labels}
|
labels={labels}
|
||||||
waluta={waluta}
|
|
||||||
cenaOpis={cenaOpis}
|
cenaOpis={cenaOpis}
|
||||||
onShowChannels={(pkg) => {
|
onShowChannels={(pkg) => {
|
||||||
setActivePkg(pkg);
|
setActivePkg(pkg);
|
||||||
@@ -163,7 +150,6 @@ function JamboxPackageCard({
|
|||||||
wsp,
|
wsp,
|
||||||
selected,
|
selected,
|
||||||
labels,
|
labels,
|
||||||
waluta,
|
|
||||||
cenaOpis,
|
cenaOpis,
|
||||||
onShowChannels,
|
onShowChannels,
|
||||||
onConfigureAddons,
|
onConfigureAddons,
|
||||||
@@ -186,7 +172,7 @@ function JamboxPackageCard({
|
|||||||
{
|
{
|
||||||
klucz: "aktywacja",
|
klucz: "aktywacja",
|
||||||
label: "Aktywacja",
|
label: "Aktywacja",
|
||||||
value: typeof installPrice === "number" ? formatMoney(installPrice, waluta) : "—",
|
value: typeof installPrice === "number" ? `${money(installPrice)} zł` : "—",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -206,15 +192,13 @@ function JamboxPackageCard({
|
|||||||
const hasPrice = typeof basePrice === "number";
|
const hasPrice = typeof basePrice === "number";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="f-card" id={`pkg-${card?.nazwa}`} data-pkg={card?.nazwa} >
|
<div class="f-card" id={`pkg-${card?.nazwa}`} data-pkg={card?.nazwa}>
|
||||||
<div class="f-card-header">
|
<div class="f-card-header">
|
||||||
<div class="f-card-name">{card.nazwa}</div>
|
<div class="f-card-name">{card.nazwa}</div>
|
||||||
|
|
||||||
<div class="f-card-price">
|
<div class="f-card-price">
|
||||||
{hasPrice ? (
|
{hasPrice ? (
|
||||||
<>
|
<>{moneyWithLabel(basePrice, cenaOpis, false)}</>
|
||||||
{formatMoney(basePrice, waluta)} <span class="opacity-80">{cenaOpis}</span>
|
|
||||||
</>
|
|
||||||
) : (
|
) : (
|
||||||
<span class="opacity-70">Wybierz opcje</span>
|
<span class="opacity-70">Wybierz opcje</span>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Markdown from "../../islands/Markdown.jsx";
|
import Markdown from "../../islands/Markdown.jsx";
|
||||||
|
import { moneyWithLabel } from "../../lib/money.js";
|
||||||
import "../../styles/cards.css";
|
import "../../styles/cards.css";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,9 +26,13 @@ export default function PhoneDbOffersCards({
|
|||||||
return (
|
return (
|
||||||
<section class="f-offers">
|
<section class="f-offers">
|
||||||
{title && <h2 class="f-section-header">{title}</h2>}
|
{title && <h2 class="f-section-header">{title}</h2>}
|
||||||
<div>
|
|
||||||
|
{description && (
|
||||||
|
<div class="mb-4">
|
||||||
<Markdown text={description} />
|
<Markdown text={description} />
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{visibleCards.length === 0 ? (
|
{visibleCards.length === 0 ? (
|
||||||
<p class="opacity-80">Brak dostępnych pakietów.</p>
|
<p class="opacity-80">Brak dostępnych pakietów.</p>
|
||||||
) : (
|
) : (
|
||||||
@@ -42,8 +47,8 @@ export default function PhoneDbOffersCards({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function PhoneOfferCard({ card }) {
|
function PhoneOfferCard({ card }) {
|
||||||
const price = card?.cena?.wartosc ?? "";
|
const priceValue = card?.cena?.wartosc;
|
||||||
const priceDesc = card?.cena?.opis ?? "zł/mies.";
|
const priceLabel = card?.cena?.opis || "zł/mies.";
|
||||||
|
|
||||||
const params = Array.isArray(card?.parametry) ? card.parametry : [];
|
const params = Array.isArray(card?.parametry) ? card.parametry : [];
|
||||||
|
|
||||||
@@ -53,8 +58,11 @@ function PhoneOfferCard({ card }) {
|
|||||||
|
|
||||||
<div class="f-card-header">
|
<div class="f-card-header">
|
||||||
<div class="f-card-name">{card.nazwa}</div>
|
<div class="f-card-name">{card.nazwa}</div>
|
||||||
|
|
||||||
<div class="f-card-price">
|
<div class="f-card-price">
|
||||||
{price} {priceDesc}
|
{typeof priceValue === "number"
|
||||||
|
? moneyWithLabel(priceValue, priceLabel, false)
|
||||||
|
: "—"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
export function money(amount) {
|
export function money(amount, decimals = true) {
|
||||||
const n = Number(amount || 0);
|
const n = Number(amount || 0);
|
||||||
|
if (decimals)
|
||||||
return n.toFixed(2).replace(".", ",");
|
return n.toFixed(2).replace(".", ",");
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function moneyWithLabel(v, cenaOpis) {
|
export function moneyWithLabel(v, cenaOpis, decimals = true) {
|
||||||
return `${money(v)} ${cenaOpis}`;
|
return `${money(v, decimals)} ${cenaOpis}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moneyPLN(v, decimals = true) {
|
||||||
|
return `${money(v, decimals)} zł`;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user