Un chat endormi sous un faisceau de lumière

Le site dort pour l'instant.
Ne le réveillez pas...

Il se réveillera quand il sera prêt.
Et si vous le souhaitez, il vous écrira.
const ENDPOINT_URL = "https://script.google.com/macros/s/AKfycbwPk-LM1ZpxuplXWlMXFBgmDEj9bFGgBN03yKhjUDITGZBM-6DcNpjeTApib0lyf14/exec"; const emailForm = document.getElementById("emailForm"); const emailField = document.getElementById("emailField"); const hpField = document.getElementById("hpField"); const note = document.getElementById("note"); const sendBtn = document.getElementById("sendBtn"); const subline = document.getElementById("subline"); let state = "idle"; // idle | confirm | sending let realEmail = ""; let firstInputTs = 0; const DEBUG = new URLSearchParams(location.search).get("debug") === "1"; function looksLikeEmail(v) { return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(String(v || "").trim()); } function setConfirmMode(email) { state = "confirm"; realEmail = email; emailField.classList.add("confirm"); emailField.classList.remove("sending"); emailField.value = `Prévenez-moi à ${email} ?`; emailField.setAttribute("readonly", "readonly"); sendBtn.classList.add("visible"); note.textContent = ""; } function setIdleMode(withValue = "") { state = "idle"; realEmail = ""; emailField.classList.remove("confirm", "sending"); emailField.removeAttribute("readonly"); emailField.value = withValue; sendBtn.classList.remove("visible"); note.textContent = ""; firstInputTs = 0; } function showSuccess() { const old = subline.innerHTML; subline.innerHTML = "Miaou ! À très bientôt !"; setTimeout(() => { subline.innerHTML = old; }, 4000); } async function sendEmail(email) { state = "sending"; emailField.classList.add("sending"); sendBtn.disabled = true; note.textContent = ""; const fillMs = firstInputTs ? Date.now() - firstInputTs : 0; const params = new URLSearchParams(); params.set("email", email); params.set("date", new Date().toISOString()); params.set("page", location.href); params.set("userAgent", navigator.userAgent); params.set("fillMs", String(fillMs)); params.set("hp", hpField.value || ""); params.set("source", "popopera-holding"); if (DEBUG) params.set("debug", "1"); try { const response = await fetch(ENDPOINT_URL, { method:"POST", body:params }); const text = await response.text().catch(() => ""); if (DEBUG) console.log("[WebApp raw]", text); let data = null; try { data = JSON.parse(text); } catch (_) {} if (!response.ok) return { ok:false, kind:"http_error", data, text }; if (data && typeof data === "object") return { ok:!!data.ok, kind:data.status||(data.ok?"ok":"error"), data, text }; const ok = /"ok"\s*:\s*true/i.test(text); return { ok, kind:ok?"ok_text":"bad_text", data:null, text }; } catch (e) { return { ok:false, kind:"network_error", error:String(e) }; } finally { emailField.classList.remove("sending"); sendBtn.disabled = false; } } // Track first input emailField.addEventListener("input", () => { if (!firstInputTs && state === "idle" && emailField.value.trim().length > 0) { firstInputTs = Date.now(); } if (state === "idle") note.textContent = ""; }); // ESC cancels confirm emailField.addEventListener("keydown", (e) => { if (e.key === "Escape" && state === "confirm") { e.preventDefault(); setIdleMode(realEmail); } }); async function handleConfirmAction() { if (state !== "confirm" || !realEmail || state === "sending") return; const result = await sendEmail(realEmail); if (DEBUG) console.log("[sendEmail]", result); if (result.ok) { showSuccess(); setIdleMode(""); } else { note.textContent = DEBUG ? `Échec: ${result.kind} ${result.data ? JSON.stringify(result.data) : (result.text || result.error || "")}` : "Un petit raté… réessayez un peu plus tard."; setIdleMode(realEmail); } } emailForm.addEventListener("submit", async (e) => { e.preventDefault(); if (state === "sending") return; if (state === "idle") { const raw = emailField.value.trim(); if (!looksLikeEmail(raw)) { note.textContent = "Adresse e-mail invalide."; return; } setConfirmMode(raw); return; } if (state === "confirm") await handleConfirmAction(); }); // Click on blue confirm field also trigger