Podmiana image w hero, Kontakt pole readonly dla danych z ofert dodanie do tresci maila
This commit is contained in:
@@ -10,6 +10,7 @@ function esc(str = "") {
|
||||
|
||||
function buildHtmlMail(form) {
|
||||
const when = new Date().toLocaleString("pl-PL");
|
||||
const offerText = (form.offerSummary || "").trim()
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="pl">
|
||||
@@ -79,6 +80,17 @@ function buildHtmlMail(form) {
|
||||
${esc(form.message)}
|
||||
</div>
|
||||
|
||||
${offerText ? `
|
||||
<div style="font-size:14px;color:#111827;margin:8px 0;font-weight:700;">
|
||||
Wybrana oferta:
|
||||
</div>
|
||||
|
||||
<div style="font-size:14px;color:#111827;white-space:pre-line;line-height:1.6;
|
||||
background:#f8fafc;border:1px solid #e5e7eb;border-radius:12px;padding:14px;">
|
||||
${esc(offerText)}
|
||||
</div>
|
||||
` : ``}
|
||||
|
||||
<div style="margin-top:16px;font-size:12px;color:#6b7280;">
|
||||
Wysłano: ${when}
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
---
|
||||
import path from "node:path";
|
||||
import DefaultLayout from "../../layouts/DefaultLayout.astro";
|
||||
import MapGoogle from "../../components/maps/MapGoogle.astro";
|
||||
import { loadYamlFile } from "../../lib/loadYaml";
|
||||
|
||||
import yaml from "js-yaml";
|
||||
import fs from "fs";
|
||||
|
||||
const data = yaml.load(
|
||||
fs.readFileSync("./src/content/contact/contact.yaml", "utf8"),
|
||||
type SeoYaml = any;
|
||||
const seo = loadYamlFile<SeoYaml>(
|
||||
path.join(process.cwd(), "src", "content", "contact", "seo.yaml"),
|
||||
);
|
||||
|
||||
const seo = yaml.load(
|
||||
fs.readFileSync("./src/content/internet-swiatlowodowy/seo.yaml", "utf8"),
|
||||
type ContactData = any;
|
||||
const data = loadYamlFile<ContactData>(
|
||||
path.join(process.cwd(), "src", "content", "contact", "contact.yaml"),
|
||||
);
|
||||
|
||||
const apiKey = import.meta.env.PUBLIC_GOOGLE_MAPS_KEY;
|
||||
@@ -25,8 +26,9 @@ const form = data.form;
|
||||
<div class="f-contact-item" set:html={data.description} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div id="form">
|
||||
<h2 class="f-section-title">{data.contactFormTitle}</h2>
|
||||
|
||||
<form id="contactForm" class="f-contact-form">
|
||||
<div class="f-contact-form-inner">
|
||||
<input
|
||||
@@ -77,7 +79,20 @@ const form = data.form;
|
||||
rows={form.message.rows}
|
||||
placeholder={form.message.placeholder}
|
||||
class="f-input"
|
||||
required></textarea>
|
||||
required
|
||||
></textarea>
|
||||
|
||||
<!-- widoczne tylko gdy jest oferta -->
|
||||
<div id="offerSummaryWrap" class="hidden">
|
||||
<textarea
|
||||
id="offerSummary"
|
||||
name="offerSummary"
|
||||
rows="6"
|
||||
class="f-input"
|
||||
readonly
|
||||
placeholder="Wybrana oferta pojawi się tutaj."
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<label class="f-rodo">
|
||||
<input type="checkbox" name="rodo" required />
|
||||
@@ -117,8 +132,6 @@ const form = data.form;
|
||||
</div>
|
||||
|
||||
<div id="toast" class="f-toast"></div>
|
||||
|
||||
<input type="hidden" name="offerConfig" id="offerConfig" />
|
||||
</section>
|
||||
|
||||
<!-- ReCaptcha v3 -->
|
||||
@@ -142,59 +155,32 @@ const form = data.form;
|
||||
}}
|
||||
>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const form = document.getElementById("contactForm");
|
||||
const formEl = document.getElementById("contactForm");
|
||||
const toast = document.getElementById("toast");
|
||||
if (!formEl) return;
|
||||
|
||||
if (!form) return;
|
||||
|
||||
form.addEventListener("submit", async (e) => {
|
||||
if (!form.reportValidity()) return;
|
||||
e.preventDefault();
|
||||
|
||||
const data = Object.fromEntries(new FormData(form).entries());
|
||||
data.rodo = form.rodo.checked;
|
||||
|
||||
const token = await grecaptcha.execute(window.FUZ_RECAPTCHA_KEY, {
|
||||
action: "submit",
|
||||
});
|
||||
data.recaptcha = token;
|
||||
|
||||
const resp = await fetch("/api/contact/contact", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
const json = await resp.json();
|
||||
|
||||
showToast(
|
||||
json.ok ? successMsg : errorMsg,
|
||||
json.ok ? "success" : "error",
|
||||
);
|
||||
|
||||
if (json.ok) form.reset();
|
||||
});
|
||||
const LS_KEY = "fuz_offer_config_v1";
|
||||
const SS_INJECTED_KEY = "fuz_offer_injected_v1";
|
||||
|
||||
function showToast(msg, type) {
|
||||
if (!toast) return;
|
||||
toast.innerHTML = `<div class="f-toast-msg ${type}">${msg}</div>`;
|
||||
toast.classList.remove("visible");
|
||||
void toast.offsetWidth;
|
||||
toast.classList.add("visible");
|
||||
|
||||
setTimeout(() => toast.classList.remove("visible"), 3000);
|
||||
}
|
||||
|
||||
// ----------
|
||||
const LS_KEY = "fuz_offer_config_v1";
|
||||
const SS_INJECTED_KEY = "fuz_offer_injected_v1";
|
||||
|
||||
function clearOfferDraft() {
|
||||
try {
|
||||
localStorage.removeItem(LS_KEY);
|
||||
sessionStorage.removeItem(SS_INJECTED_KEY);
|
||||
|
||||
const hidden = document.getElementById("offerConfig");
|
||||
if (hidden) hidden.value = "";
|
||||
const wrap = document.getElementById("offerSummaryWrap");
|
||||
if (wrap) wrap.classList.add("hidden");
|
||||
|
||||
const offerSummary = document.getElementById("offerSummary");
|
||||
if (offerSummary) offerSummary.value = "";
|
||||
} catch {}
|
||||
}
|
||||
|
||||
@@ -207,9 +193,9 @@ const form = data.form;
|
||||
|
||||
const payload = JSON.parse(raw);
|
||||
|
||||
const msg = document.querySelector('textarea[name="message"]');
|
||||
const subject = document.querySelector('input[name="subject"]');
|
||||
const hidden = document.getElementById("offerConfig");
|
||||
const subject = formEl.querySelector('input[name="subject"]');
|
||||
const wrap = document.getElementById("offerSummaryWrap");
|
||||
const offerSummary = document.getElementById("offerSummary");
|
||||
|
||||
const offerText =
|
||||
typeof payload?.message === "string" && payload.message.trim()
|
||||
@@ -218,19 +204,13 @@ const form = data.form;
|
||||
|
||||
if (!offerText) return;
|
||||
|
||||
if (wrap) wrap.classList.remove("hidden");
|
||||
|
||||
if (subject && !subject.value) {
|
||||
subject.value = `Zapytanie: ${payload?.pkg?.name || "Oferta"}`;
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
const marker = "Wybrana oferta:";
|
||||
const alreadyHas = msg.value && msg.value.includes(marker);
|
||||
if (!alreadyHas) {
|
||||
msg.value = (msg.value ? msg.value + "\n\n" : "") + offerText;
|
||||
}
|
||||
}
|
||||
|
||||
if (hidden) hidden.value = offerText;
|
||||
if (offerSummary) offerSummary.value = offerText;
|
||||
|
||||
sessionStorage.setItem(SS_INJECTED_KEY, "1");
|
||||
} catch {}
|
||||
@@ -238,21 +218,43 @@ const form = data.form;
|
||||
|
||||
hydrateOfferIntoForm();
|
||||
|
||||
function onSubmitSuccessCleanup() {
|
||||
clearOfferDraft();
|
||||
}
|
||||
window.addEventListener("pagehide", clearOfferDraft);
|
||||
window.addEventListener("beforeunload", clearOfferDraft);
|
||||
|
||||
function onLeaveCleanup() {
|
||||
clearOfferDraft();
|
||||
}
|
||||
formEl.addEventListener("submit", async (e) => {
|
||||
if (!formEl.reportValidity()) return;
|
||||
e.preventDefault();
|
||||
|
||||
window.addEventListener("pagehide", onLeaveCleanup);
|
||||
window.addEventListener("beforeunload", onLeaveCleanup);
|
||||
if (json.ok) {
|
||||
form.reset();
|
||||
onSubmitSuccessCleanup();
|
||||
}
|
||||
// ----------
|
||||
try {
|
||||
const data = Object.fromEntries(new FormData(formEl).entries());
|
||||
data.rodo = formEl.rodo?.checked === true;
|
||||
|
||||
const token = await grecaptcha.execute(window.FUZ_RECAPTCHA_KEY, {
|
||||
action: "submit",
|
||||
});
|
||||
data.recaptcha = token;
|
||||
|
||||
const resp = await fetch("/api/contact/contact", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
const json = await resp.json().catch(() => ({}));
|
||||
|
||||
showToast(
|
||||
json?.ok ? successMsg : errorMsg,
|
||||
json?.ok ? "success" : "error",
|
||||
);
|
||||
|
||||
if (json?.ok) {
|
||||
formEl.reset();
|
||||
clearOfferDraft();
|
||||
}
|
||||
} catch {
|
||||
showToast(errorMsg, "error");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</DefaultLayout>
|
||||
|
||||
Reference in New Issue
Block a user