diff --git a/src/app/components/AnalyticsEvents.js b/src/app/components/AnalyticsEvents.js new file mode 100644 index 0000000..cb9f4f9 --- /dev/null +++ b/src/app/components/AnalyticsEvents.js @@ -0,0 +1,18 @@ +"use client"; + +import { useEffect } from "react"; +import { eventForHref, trackEvent } from "@/lib/analytics"; + +// One site-wide listener, so every call/text/email/review link is tracked. +export default function AnalyticsEvents() { + useEffect(() => { + function handleClick(event) { + const link = event.target.closest?.("a[href]"); + const name = link && eventForHref(link.getAttribute("href")); + if (name) trackEvent(name); + } + document.addEventListener("click", handleClick); + return () => document.removeEventListener("click", handleClick); + }, []); + return null; +} diff --git a/src/app/components/ContactForm.js b/src/app/components/ContactForm.js index 31988e7..470a4a0 100644 --- a/src/app/components/ContactForm.js +++ b/src/app/components/ContactForm.js @@ -1,67 +1,160 @@ -import styles from "./ContactForm.module.css"; +"use client"; +import { useState } from "react"; +import styles from "./ContactForm.module.css"; +import { business, links } from "@/lib/site"; +import { trackEvent } from "@/lib/analytics"; + +const FORM_ACTION = "https://form.taxi/s/es9ddva1"; + +const devices = ["Laptop", "Desktop PC", "Chromebook", "Other"]; +const problems = [ + "Won't turn on or won't start", + "Cracked or broken screen", + "Running slow / upgrade", + "Virus, pop-ups or scam", + "Battery or charging", + "Moving files to a new computer", + "Windows 10 / Windows 11", + "Business IT support", + "Something else", +]; +const contactMethods = ["Call", "Text", "Email"]; + +// Submits to form.taxi with JavaScript for an inline success message; without +// JavaScript the form still posts normally. export default function ContactForm() { + const [status, setStatus] = useState("idle"); + + async function handleSubmit(event) { + event.preventDefault(); + setStatus("sending"); + try { + const response = await fetch(FORM_ACTION, { + method: "POST", + headers: { Accept: "application/json" }, + body: new FormData(event.currentTarget), + }); + const result = await response.json().catch(() => ({})); + if (!response.ok || !result.success) throw new Error("Submit failed"); + setStatus("sent"); + trackEvent("submit_quote_form"); + } catch { + setStatus("error"); + } + } + + if (status === "sent") { + return ( +
+ I'll usually reply the same day during business hours (Monday + to Friday, 9am to 6pm). If it's urgent, call or text{" "} + + {business.phone} + + . +
++ Tell me what's going on and I'll get back to you, usually the + same day during business hours. +
+ The quickest way to reach me is a call or text. I'm{" "} + {business.ownerName}, and I'll be the one fixing your computer. +
++ Onsite visits and pickup across{" "} + {business.serviceArea.join(", ")}. The travel fee depends on + distance. +
++ See{" "} + + prices + {" "} + and{" "} + + common questions + + . +
+