diff --git a/apps/web/src/app/privacy/page.tsx b/apps/web/src/app/privacy/page.tsx index a132563..901e45c 100644 --- a/apps/web/src/app/privacy/page.tsx +++ b/apps/web/src/app/privacy/page.tsx @@ -84,6 +84,13 @@ export default function PrivacyPage() { collected from your visit. We do not use Google Analytics, advertising pixels, or similar third-party tracking tools on the Site.

+

+ Alongside page views, we count two things you do on purpose: that someone began filling in + the contact form, and that someone sent it. These are counters, not contents. They record + which of the two forms it was and nothing you typed, and like everything else here they are + not collected at all if Do Not Track or Global Privacy Control is on. We use them to tell + whether a change to the site helped or hurt, rather than guessing. +

Server logs

diff --git a/apps/web/src/components/contact/contact-form.tsx b/apps/web/src/components/contact/contact-form.tsx index 243a3cf..ce29bbe 100644 --- a/apps/web/src/components/contact/contact-form.tsx +++ b/apps/web/src/components/contact/contact-form.tsx @@ -1,10 +1,11 @@ -'use client'; -import { useActionState } from 'react'; -import { useFormStatus } from 'react-dom'; -import { submitContactForm } from '@/actions/submit-contact'; -import { TurnstileWidget } from './turnstile-widget'; -import { useState, useEffect, useRef } from 'react'; -import { Button } from '@repo/ui/components/button'; +"use client"; +import { useActionState } from "react"; +import { useFormStatus } from "react-dom"; +import { submitContactForm } from "@/actions/submit-contact"; +import { TurnstileWidget } from "./turnstile-widget"; +import { useState, useEffect, useRef } from "react"; +import { Button } from "@repo/ui/components/button"; +import { EVENTS, track } from "@/lib/analytics"; function SubmitButton({ label = "Send Message" }: { label?: string }) { const { pending } = useFormStatus(); @@ -21,50 +22,68 @@ function SubmitButton({ label = "Send Message" }: { label?: string }) { } interface ContactFormProps { - source?: 'inquiry' | 'support'; + source?: "inquiry" | "support"; } -export function ContactForm({ source = 'inquiry' }: ContactFormProps) { - const [state, formAction] = useActionState(submitContactForm, { success: false, message: '' }); - const [token, setToken] = useState(''); +export function ContactForm({ source = "inquiry" }: ContactFormProps) { + const [state, formAction] = useActionState(submitContactForm, { + success: false, + message: "", + }); + const [token, setToken] = useState(""); const formRef = useRef(null); + // Fires once per mounted form, on the first real edit. A focus would count a visitor who + // tabbed through on the way somewhere else; typing is intent. + const startedRef = useRef(false); - const isSupport = source === 'support'; + const noteStart = () => { + if (startedRef.current) return; + startedRef.current = true; + track(EVENTS.contactStarted, { source }); + }; + + const isSupport = source === "support"; // Reset form on successful submission useEffect(() => { if (state.success && formRef.current) { formRef.current.reset(); - setToken(''); + setToken(""); + startedRef.current = false; + track(EVENTS.contactSubmitted, { source }); } - }, [state.success]); + }, [state.success, source]); return (

-
-
+
+
-
-

- {isSupport ? 'Send Feedback' : 'Project Inquiry'} -

-

- {isSupport - ? 'Found a bug? Have a feature request? We read every message and typically respond within 24 hours.' - : 'Tell us about your technical challenges. From Medusa v2 migrations to real-time custom engines, we\'re ready to architect your solution.'} -

-
+
+

+ {isSupport ? "Send Feedback" : "Project Inquiry"} +

+

+ {isSupport + ? "Found a bug? Have a feature request? We read every message and typically respond within 24 hours." + : "Tell us about your technical challenges. From Medusa v2 migrations to real-time custom engines, we're ready to architect your solution."} +

+
-
-
-