feat(contact): extract shared ContactForm and add per-subdomain contact pages

Refactor the monolithic main-site contact page into a reusable
<ContactForm> component that encapsulates the Turnstile widget, cooldown
timer, email-verification flow, and tRPC submission. The main
/contact route becomes a thin wrapper that supplies the site-specific
disclaimer subline and Life-and-Lineage FAQ accordion (now exported as
<LineageContactQuestions> for reuse).

Add per-subdomain contact routes (gaze, inputhalo, lineage, nessa) that
render the shared component, with site-aware subject prefix, recipient,
heading, and PageHead metadata derived via useSite() from CONTACT_CONTEXT.

Introduce src/lib/contact-config.ts (with tests) centralizing the contact
recipient/sender addresses and subject building. The misc.sendContactRequest
mutation accepts an optional subjectPrefix (defaulting to "freno.me") so
inbound call sites continue emitting byte-identical legacy subjects, while
subdomain submissions route distinct subjects (e.g. "[Gaze] Contact Request")
to the same inbox.
This commit is contained in:
2026-07-23 12:25:13 -04:00
parent 1cc16313d5
commit a7ad581ed2
9 changed files with 1016 additions and 513 deletions

View File

@@ -0,0 +1,21 @@
import { ContactForm } from "~/components/ContactForm";
/**
* Nessa contact page (`nessa.freno.me/contact`).
*
* Thin wrapper over the shared `<ContactForm>` (task 09). Site awareness —
* subject prefix `[Nessa]`, recipient label, heading, and PageHead metadata —
* is derived from `useSite()` inside the component via
* `CONTACT_CONTEXT.nessa`, so this route needs no explicit props.
*
* vercel.json rewrites `nessa.freno.me/*` → the internal `/nessa/*` route
* prefix; the browser URL stays `nessa.freno.me/contact` so the canonical and
* Turnstile origin resolve correctly.
*
* Acceptance: `nessa.localhost:3000/contact` renders the contact form with
* Nessa branding; submissions email `michael@freno.me` with subject
* `[Nessa] Contact Request`.
*/
export default function NessaContactPage() {
return <ContactForm />;
}