Przebudowa stron na indywidualne karty , pobierane z bazy danych
This commit is contained in:
71
src/pages/api/internet.js
Normal file
71
src/pages/api/internet.js
Normal file
@@ -0,0 +1,71 @@
|
||||
// src/pages/api/switches/internet.js
|
||||
import Database from "better-sqlite3";
|
||||
|
||||
const DB_PATH = "./src/data/ServicesRange.db";
|
||||
|
||||
function getDb() {
|
||||
return new Database(DB_PATH, { readonly: true });
|
||||
}
|
||||
|
||||
export function GET() {
|
||||
const db = getDb();
|
||||
|
||||
try {
|
||||
const buildingTypes = db
|
||||
.prepare("SELECT code, label FROM jambox_building_types ORDER BY code")
|
||||
.all();
|
||||
|
||||
const contractTypes = db
|
||||
.prepare(
|
||||
"SELECT code, label FROM jambox_contract_types ORDER BY code"
|
||||
)
|
||||
.all();
|
||||
|
||||
const switches = [
|
||||
{
|
||||
id: "budynek",
|
||||
etykieta: "Rodzaj budynku",
|
||||
domyslny: buildingTypes[0]?.code ?? 1,
|
||||
title: "Zmień rodzaj budynku by zobaczyć odpowiednie ceny",
|
||||
opcje: buildingTypes.map((b) => ({
|
||||
id: b.code, // 1,2,...
|
||||
nazwa: b.label,
|
||||
})),
|
||||
},
|
||||
{
|
||||
id: "umowa",
|
||||
etykieta: "Okres umowy",
|
||||
domyslny: contractTypes[0]?.code ?? 1,
|
||||
title: "Wybierz okres umowy by zobaczyć odpowiednie ceny",
|
||||
opcje: contractTypes.map((c) => ({
|
||||
id: c.code, // 1,2,...
|
||||
nazwa: c.label,
|
||||
})),
|
||||
},
|
||||
];
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({ ok: true, data: switches }),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"Cache-Control": "public, max-age=60",
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("❌ Błąd w /api/switches/internet:", err);
|
||||
return new Response(
|
||||
JSON.stringify({ ok: false, error: err.message || "DB_ERROR" }),
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
110
src/pages/api/internet/plans.js
Normal file
110
src/pages/api/internet/plans.js
Normal file
@@ -0,0 +1,110 @@
|
||||
// src/pages/api/internet/plans.js
|
||||
import Database from "better-sqlite3";
|
||||
|
||||
const DB_PATH = "./src/data/ServicesRange.db";
|
||||
|
||||
function getDb() {
|
||||
return new Database(DB_PATH, { readonly: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/internet/plans?building=1|2&contract=1|2
|
||||
*/
|
||||
export function GET({ url }) {
|
||||
const buildingParam = url.searchParams.get("building");
|
||||
const contractParam = url.searchParams.get("contract");
|
||||
|
||||
const building = buildingParam ? Number(buildingParam) : 1;
|
||||
const contract = contractParam ? Number(contractParam) : 1;
|
||||
|
||||
const db = getDb();
|
||||
|
||||
try {
|
||||
const stmt = db.prepare(
|
||||
`
|
||||
SELECT
|
||||
p.id AS plan_id,
|
||||
p.name AS plan_name,
|
||||
p.popular AS plan_popular,
|
||||
|
||||
pr.price_monthly AS price_monthly,
|
||||
pr.price_installation AS price_installation,
|
||||
|
||||
f.id AS feature_id,
|
||||
f.label AS feature_label,
|
||||
fv.value AS feature_value
|
||||
|
||||
FROM internet_plans p
|
||||
LEFT JOIN internet_plan_prices pr
|
||||
ON pr.plan_id = p.id
|
||||
AND pr.building_type = ?
|
||||
AND pr.contract_type = ?
|
||||
|
||||
LEFT JOIN internet_plan_feature_values fv
|
||||
ON fv.plan_id = p.id
|
||||
|
||||
LEFT JOIN internet_features f
|
||||
ON f.id = fv.feature_id
|
||||
|
||||
ORDER BY p.id ASC, f.id ASC;
|
||||
`.trim()
|
||||
);
|
||||
|
||||
const rows = stmt.all(building, contract);
|
||||
|
||||
// grupowanie do struktury: jeden plan = jedna karta
|
||||
const byPlan = new Map();
|
||||
|
||||
for (const row of rows) {
|
||||
if (!byPlan.has(row.plan_id)) {
|
||||
byPlan.set(row.plan_id, {
|
||||
id: row.plan_id,
|
||||
code: row.plan_code,
|
||||
name: row.plan_name,
|
||||
popular: !!row.plan_popular,
|
||||
price_monthly: row.price_monthly,
|
||||
price_installation: row.price_installation,
|
||||
features: [], // później wypełniamy
|
||||
});
|
||||
}
|
||||
|
||||
if (row.feature_id) {
|
||||
byPlan.get(row.plan_id).features.push({
|
||||
id: row.feature_id,
|
||||
label: row.feature_label,
|
||||
value: row.feature_value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const data = Array.from(byPlan.values());
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
ok: true,
|
||||
building,
|
||||
contract,
|
||||
count: data.length,
|
||||
data,
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"Cache-Control": "public, max-age=30",
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("❌ Błąd w /api/internet/plans:", err);
|
||||
return new Response(
|
||||
JSON.stringify({ ok: false, error: "DB_ERROR" }),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json; charset=utf-8" },
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
152
src/pages/api/jambox/base-packages.js
Normal file
152
src/pages/api/jambox/base-packages.js
Normal file
@@ -0,0 +1,152 @@
|
||||
// src/pages/api/jambox/base-packages.js
|
||||
import Database from "better-sqlite3";
|
||||
|
||||
const DB_PATH = "./src/data/ServicesRange.db"; // dostosuj, jeśli masz gdzie indziej
|
||||
|
||||
function getDb() {
|
||||
return new Database(DB_PATH, { readonly: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/jambox/base-packages
|
||||
* ?source=PLUS|EVIO
|
||||
* &building=1|2 (1=jednorodzinny, 2=wielorodzinny)
|
||||
* &contract=1|2 (1=24m, 2=bezterminowa)
|
||||
*/
|
||||
export function GET({ url }) {
|
||||
const sourceParam = url.searchParams.get("source");
|
||||
const source = sourceParam ? sourceParam.toUpperCase() : null;
|
||||
|
||||
const buildingParam = url.searchParams.get("building");
|
||||
const contractParam = url.searchParams.get("contract");
|
||||
const building = buildingParam ? Number(buildingParam) : null;
|
||||
const contract = contractParam ? Number(contractParam) : null;
|
||||
|
||||
const db = getDb();
|
||||
|
||||
try {
|
||||
let rows = [];
|
||||
const hasVariant =
|
||||
Number.isInteger(building) && Number.isInteger(contract);
|
||||
|
||||
if (source === "PLUS" || source === "EVIO") {
|
||||
if (hasVariant) {
|
||||
// pakiety + ceny dla danego budynku/umowy
|
||||
const stmt = db.prepare(
|
||||
`
|
||||
SELECT
|
||||
p.id,
|
||||
p.source,
|
||||
p.tid,
|
||||
p.name,
|
||||
p.slug,
|
||||
p.sort_order,
|
||||
p.updated_at,
|
||||
pr.price_monthly,
|
||||
pr.price_installation,
|
||||
pr.currency
|
||||
FROM jambox_base_packages p
|
||||
LEFT JOIN jambox_base_package_prices pr
|
||||
ON pr.package_id = p.id
|
||||
AND pr.building_type = ?
|
||||
AND pr.contract_type = ?
|
||||
WHERE p.source = ?
|
||||
ORDER BY p.sort_order ASC, p.name ASC;
|
||||
`.trim()
|
||||
);
|
||||
rows = stmt.all(building, contract, source);
|
||||
} else {
|
||||
// tylko pakiety, bez cen
|
||||
const stmt = db.prepare(
|
||||
`
|
||||
SELECT
|
||||
p.id,
|
||||
p.source,
|
||||
p.tid,
|
||||
p.name,
|
||||
p.slug,
|
||||
p.sort_order,
|
||||
p.updated_at
|
||||
FROM jambox_base_packages p
|
||||
WHERE p.source = ?
|
||||
ORDER BY p.sort_order ASC, p.name ASC;
|
||||
`.trim()
|
||||
);
|
||||
rows = stmt.all(source);
|
||||
}
|
||||
} else {
|
||||
// bez filtra source (raczej nie użyjesz, ale niech będzie poprawnie)
|
||||
if (hasVariant) {
|
||||
const stmt = db.prepare(
|
||||
`
|
||||
SELECT
|
||||
p.id,
|
||||
p.source,
|
||||
p.tid,
|
||||
p.name,
|
||||
p.slug,
|
||||
p.sort_order,
|
||||
p.updated_at,
|
||||
pr.price_monthly,
|
||||
pr.price_installation,
|
||||
pr.currency
|
||||
FROM jambox_base_packages p
|
||||
LEFT JOIN jambox_base_package_prices pr
|
||||
ON pr.package_id = p.id
|
||||
AND pr.building_type = ?
|
||||
AND pr.contract_type = ?
|
||||
ORDER BY p.source ASC, p.sort_order ASC, p.name ASC;
|
||||
`.trim()
|
||||
);
|
||||
rows = stmt.all(building, contract);
|
||||
} else {
|
||||
const stmt = db.prepare(
|
||||
`
|
||||
SELECT
|
||||
p.id,
|
||||
p.source,
|
||||
p.tid,
|
||||
p.name,
|
||||
p.slug,
|
||||
p.sort_order,
|
||||
p.updated_at
|
||||
FROM jambox_base_packages p
|
||||
ORDER BY p.source ASC, p.sort_order ASC, p.name ASC;
|
||||
`.trim()
|
||||
);
|
||||
rows = stmt.all();
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
ok: true,
|
||||
source: source ?? "ALL",
|
||||
building,
|
||||
contract,
|
||||
count: rows.length,
|
||||
data: rows,
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"Cache-Control": "public, max-age=60",
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("❌ Błąd odczytu z bazy jambox_base_packages:", err);
|
||||
return new Response(
|
||||
JSON.stringify({ ok: false, error: "DB_ERROR" }),
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
85
src/pages/api/phone/plans.js
Normal file
85
src/pages/api/phone/plans.js
Normal file
@@ -0,0 +1,85 @@
|
||||
import Database from "better-sqlite3";
|
||||
|
||||
const DB_PATH = "./src/data/ServicesRange.db";
|
||||
|
||||
export async function GET() {
|
||||
const db = new Database(DB_PATH, { readonly: true });
|
||||
|
||||
try {
|
||||
const stmt = db.prepare(`
|
||||
SELECT
|
||||
p.id AS plan_id,
|
||||
p.name AS plan_name,
|
||||
IFNULL(p.popular, 0) AS plan_popular,
|
||||
p.price_monthly AS price_monthly,
|
||||
p.currency AS currency,
|
||||
|
||||
f.id AS feature_id,
|
||||
f.label AS feature_label,
|
||||
fv.value AS feature_value
|
||||
|
||||
FROM phone_plans p
|
||||
LEFT JOIN phone_plan_feature_values fv
|
||||
ON fv.plan_id = p.id
|
||||
LEFT JOIN phone_features f
|
||||
ON f.id = fv.feature_id
|
||||
ORDER BY p.id ASC, f.id ASC
|
||||
`);
|
||||
|
||||
const rows = stmt.all();
|
||||
|
||||
const byPlan = new Map();
|
||||
|
||||
for (const row of rows) {
|
||||
if (!byPlan.has(row.plan_id)) {
|
||||
byPlan.set(row.plan_id, {
|
||||
id: row.plan_id,
|
||||
code: row.plan_code,
|
||||
name: row.plan_name,
|
||||
popular: !!row.plan_popular,
|
||||
price_monthly: row.price_monthly,
|
||||
currency: row.currency || "PLN",
|
||||
features: [],
|
||||
});
|
||||
}
|
||||
|
||||
if (row.feature_id) {
|
||||
byPlan.get(row.plan_id).features.push({
|
||||
id: row.feature_id,
|
||||
label: row.feature_label,
|
||||
value: row.feature_value,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const data = Array.from(byPlan.values());
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
ok: true,
|
||||
count: data.length,
|
||||
data,
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("❌ Błąd w /api/phone/plans:", err);
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
ok: false,
|
||||
error: err.message || "DB_ERROR",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
import DefaultLayout from "../../layouts/DefaultLayout.astro";
|
||||
import Hero from "../../components/hero/Hero.astro";
|
||||
import OffersSwitches from "../../islands/Offers/OffersSwitches.jsx";
|
||||
import InternetDbOffersCards from "../../islands/OffersInternetCards.jsx";
|
||||
import SectionRenderer from "../../components/sections/SectionRenderer.astro";
|
||||
import Markdown from "../../islands/Markdown.jsx";
|
||||
import OffersIsland from "../../islands/OffersIsland.jsx";
|
||||
|
||||
import yaml from "js-yaml";
|
||||
import fs from "fs";
|
||||
@@ -11,52 +10,19 @@ import fs from "fs";
|
||||
const seo = yaml.load(
|
||||
fs.readFileSync("./src/content/internet-swiatlowodowy/seo.yaml", "utf8"),
|
||||
);
|
||||
const hero = yaml.load(
|
||||
fs.readFileSync("./src/content/internet-swiatlowodowy/hero.yaml", "utf8"),
|
||||
);
|
||||
const page = yaml.load(
|
||||
fs.readFileSync("./src/content/internet-swiatlowodowy/page.yaml", "utf8"),
|
||||
);
|
||||
|
||||
type Paragraph = {
|
||||
title?: string;
|
||||
content: string;
|
||||
};
|
||||
|
||||
const data = yaml.load(
|
||||
fs.readFileSync("./src/content/internet-swiatlowodowy/offers.yaml", "utf8"),
|
||||
);
|
||||
const first = page.paragraphs[0];
|
||||
const rest = page.paragraphs.slice(1);
|
||||
---
|
||||
|
||||
<DefaultLayout seo={seo}>
|
||||
<Hero {...hero} />
|
||||
|
||||
<section class="f-section">
|
||||
<div class="f-section-grid-single md:grid-cols-1">
|
||||
{page.title.map((line: any) => <h1 class="f-section-title">{line}</h1>)}
|
||||
{first.title && <h3>{first.title}</h3>}
|
||||
<Markdown text={first.content} />
|
||||
<h1 class="f-section-title">Internet światłowodowy</h1>
|
||||
<div class="fuz-markdown max-w-none">
|
||||
<p>Wybierz rodzaj budynku i czas trwania umowy</p>
|
||||
</div>
|
||||
<OffersSwitches client:load />
|
||||
<InternetDbOffersCards client:load />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="f-section">
|
||||
<div class="f-section-grid-single md:grid-cols-1">
|
||||
<OffersIsland client:load data={data} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{
|
||||
rest.map((p: Paragraph) => (
|
||||
<section class="f-section">
|
||||
<div class="f-section-grid-single md:grid-cols-1">
|
||||
{p.title && <h3 class="f-section-title">{p.title}</h3>}
|
||||
<Markdown text={p.content.replace(/\n/g, "\n\n")} />
|
||||
</div>
|
||||
</section>
|
||||
))
|
||||
}
|
||||
|
||||
<SectionRenderer src="./src/content/internet-swiatlowodowy/section.yaml" />
|
||||
</DefaultLayout>
|
||||
|
||||
@@ -6,6 +6,7 @@ import Markdown from "../../islands/Markdown.jsx";
|
||||
import Modal from "../../islands/Modal.jsx";
|
||||
import OffersIsland from "../../islands/OffersIsland.jsx";
|
||||
import JamboxMozliwosci from "../../components/sections/SectionJamboxMozliwosci.astro";
|
||||
import JamboxBasePackages from "../../islands/Offers/JamboxBasePackages.jsx";
|
||||
|
||||
import yaml from "js-yaml";
|
||||
import fs from "fs";
|
||||
@@ -48,12 +49,18 @@ const rest = page.paragraphs.slice(1);
|
||||
|
||||
<section class="f-section">
|
||||
<div class="f-section-grid-single md:grid-cols-1 max-w-6xl mx-auto">
|
||||
|
||||
<JamboxBasePackages
|
||||
client:load
|
||||
source=""
|
||||
title=""/>
|
||||
|
||||
<OffersIsland client:load data={data} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- <OffersIsland client:load data={data} /> -->
|
||||
|
||||
{
|
||||
rest.map((p: Paragraph) => (
|
||||
<section class="f-section">
|
||||
|
||||
@@ -146,7 +146,7 @@ const mapStyleId = "8e0a97af9476f2d3";
|
||||
<div class="f-info-header">
|
||||
<div class="f-info-heading">
|
||||
${
|
||||
result.availableFiber
|
||||
result.available
|
||||
? `<span class="ok">✔</span> Internet światłowodowy dostępny`
|
||||
: `<span class="no">✖</span> Światłowód niedostępny`
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
---
|
||||
import DefaultLayout from "../../layouts/DefaultLayout.astro";
|
||||
import Hero from "../../components/hero/Hero.astro";
|
||||
import SectionRenderer from "../../components/sections/SectionRenderer.astro";
|
||||
import Markdown from "../../islands/Markdown.jsx";
|
||||
import OffersIsland from "../../islands/OffersIsland.jsx";
|
||||
import OffersPhoneCards from "../../islands/OffersPhoneCards.jsx";
|
||||
|
||||
import yaml from "js-yaml";
|
||||
import fs from "fs";
|
||||
@@ -11,44 +9,18 @@ import fs from "fs";
|
||||
const seo = yaml.load(
|
||||
fs.readFileSync("./src/content/telefon/seo.yaml", "utf8"),
|
||||
);
|
||||
const hero = yaml.load(
|
||||
fs.readFileSync("./src/content/telefon/hero.yaml", "utf8"),
|
||||
);
|
||||
const page = yaml.load(
|
||||
fs.readFileSync("./src/content/telefon/page.yaml", "utf8"),
|
||||
);
|
||||
|
||||
type Paragraph = {
|
||||
title?: string;
|
||||
content: string;
|
||||
};
|
||||
|
||||
const data = yaml.load(
|
||||
fs.readFileSync("./src/content/telefon/offers.yaml", "utf8"),
|
||||
);
|
||||
const first = page.paragraphs[0];
|
||||
const rest = page.paragraphs.slice(1);
|
||||
---
|
||||
|
||||
<DefaultLayout seo={seo}>
|
||||
<Hero {...hero} />
|
||||
|
||||
<section class="f-section">
|
||||
<div class="f-section-grid-single md:grid-cols-1">
|
||||
{page.title.map((line: any) => <h1 class="f-section-title">{line}</h1>)}
|
||||
{first.title && <h3>{first.title}</h3>}
|
||||
<Markdown text={first.content} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="f-section">
|
||||
<div class="f-section-grid-single md:grid-cols-1">
|
||||
<OffersIsland client:load data={data} />
|
||||
<h1 class="f-section-title">Usługa telefonu</h1>
|
||||
<OffersPhoneCards client:load />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- <OffersIsland client:load data={data} /> -->
|
||||
{
|
||||
<!-- {
|
||||
rest.map((p: Paragraph) => (
|
||||
<section class="f-section">
|
||||
<div class="f-section-grid-single md:grid-cols-1">
|
||||
@@ -57,7 +29,7 @@ const rest = page.paragraphs.slice(1);
|
||||
</div>
|
||||
</section>
|
||||
))
|
||||
}
|
||||
} -->
|
||||
|
||||
<SectionRenderer src="./src/content/telefon/section.yaml" />
|
||||
</DefaultLayout>
|
||||
|
||||
Reference in New Issue
Block a user