Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 8x 8x 8x 8x 9x 9x 8x 8x 8x 8x 3x 3x 3x 3x 8x 7x 7x 8x 8x 8x 8x 8x 8x 8x 1x 1x 7x 7x 7x 6x 6x 5x 5x 5x 5x 1x 1x 1x 1x | // Client script for the standalone Free Consultation Booking form.
// Lightweight, framework-free (matches the marketplace's minimal-JS pattern).
// Client checks are for fast feedback only — 'api/book-consultation.ts' is the
// authoritative validator (shared 'lib/consultation.ts' rules).
//
// Exposed as an init function (not a module side effect) so it is unit-testable
// with a jsdom fixture; the .astro component calls it on load.
// Basic Indian-mobile shape check (server does the authoritative parse).
function looksLikeIndianMobile(raw: string): boolean {
let digits = raw.replace(/\D/g, "");
if (digits.length === 12 && digits.startsWith("91")) digits = digits.slice(2);
if (digits.length === 11 && digits.startsWith("0")) digits = digits.slice(1);
return /^[6-9]\d{9}$/.test(digits);
}
export function initConsultationBooking(): void {
const form = document.getElementById(
"consultation-form",
) as HTMLFormElement | null;
if (!form) return;
const confirmation = document.getElementById("consultation-confirmation");
const errorEl = document.getElementById("cb-error");
const submitBtn = document.getElementById(
"cb-submit",
) as HTMLButtonElement | null;
const refEl = document.getElementById("cb-ref");
function showError(message: string): void {
Iif (!errorEl) return;
errorEl.textContent = message;
errorEl.classList.remove("hidden");
errorEl.focus?.();
}
function clearError(): void {
if (!errorEl) return;
errorEl.textContent = "";
errorEl.classList.add("hidden");
}
form.addEventListener("submit", async (e) => {
e.preventDefault();
clearError();
const fd = new FormData(form);
const phone = String(fd.get("phone") ?? "").trim();
const details = String(fd.get("details") ?? "").trim();
// Client-side quick check (mirrors server messages).
if (!phone || !looksLikeIndianMobile(phone)) {
showError("Enter a valid 10-digit Indian mobile number.");
return;
}
if (submitBtn) submitBtn.disabled = true;
try {
const res = await fetch("/api/book-consultation", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
phone,
details: details || undefined,
}),
});
const json = (await res.json().catch(() => ({}))) as {
success?: boolean;
error?: string;
data?: { bookingRef?: string };
};
if (res.ok && json.success && json.data) {
if (refEl) refEl.textContent = json.data.bookingRef ?? "—";
form.classList.add("hidden");
confirmation?.classList.remove("hidden");
confirmation?.scrollIntoView?.({
behavior: "smooth",
block: "center",
});
} else {
showError(json.error ?? "Something went wrong. Please try again.");
Eif (submitBtn) submitBtn.disabled = false;
}
} catch {
showError("Could not submit right now. Please try again.");
Eif (submitBtn) submitBtn.disabled = false;
}
});
}
|