diff --git a/scripts/routeMeta.mjs b/scripts/routeMeta.mjs index 302df59..68d1e10 100644 --- a/scripts/routeMeta.mjs +++ b/scripts/routeMeta.mjs @@ -539,7 +539,7 @@ export const ROUTE_META = { "/waitlist/ai-agent-toolkit": { title: "Join the AI Agent Toolkit Waitlist · Fil One", description: - "Get early access to the Fil One AI Agent Toolkit — connect storage to Claude, Cursor, and your agent stack via MCP and OAuth.", + "Get early access to the Fil One AI Agent Toolkit. Connect storage to Claude, Cursor, and your agent stack via MCP and OAuth.", }, "/about": { title: "About · Fil One", diff --git a/src/pages/AgentToolkitWaitlistPage.tsx b/src/pages/AgentToolkitWaitlistPage.tsx index e4da71a..e592a24 100644 --- a/src/pages/AgentToolkitWaitlistPage.tsx +++ b/src/pages/AgentToolkitWaitlistPage.tsx @@ -2,13 +2,21 @@ import { useState } from "react"; import { Check } from "@phosphor-icons/react"; import PlatformNavbar from "@/components/PlatformNavbar"; import Footer from "@/components/Footer"; -import { BackButton } from "@/components/LandingPrimitives"; +import { BackButton, SectionLabel } from "@/components/LandingPrimitives"; import { useSeo } from "@/hooks/useSeo"; import { - HS_PORTAL_ID, + FIELD_INPUT_CLASS, + TextField, + TextAreaField, + SelectField, + SubmitButton, + FormSuccess, + FormError, +} from "@/components/FormControls"; +import { HS_AGENT_TOOLKIT_WAITLIST_FORM_GUID, HS_MARKETING_SUBSCRIPTION_TYPE_ID, - getHubSpotContext, + submitHubSpotForm, } from "@/lib/hubspot"; const TIMELINES = [ @@ -37,52 +45,10 @@ const TOOLS = [ "Other", ]; -const inputStyle: React.CSSProperties = { - width: "100%", - border: "1px solid rgba(0,0,0,0.10)", - borderRadius: 10, - padding: "10px 14px", - fontFamily: "'Funnel Sans', sans-serif", - fontWeight: 400, - fontSize: 14.5, - color: "#09090B", - backgroundColor: "#FFFFFF", - outline: "none", - transition: "border-color 150ms ease", -}; - -const selectStyle: React.CSSProperties = { - ...inputStyle, - appearance: "none", - WebkitAppearance: "none", - backgroundImage: `url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2352525B' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")`, - backgroundRepeat: "no-repeat", - backgroundPosition: "right 14px center", - paddingRight: 36, - cursor: "pointer", -}; - -const labelStyle: React.CSSProperties = { - fontFamily: "'Funnel Sans', sans-serif", - fontWeight: 500, - fontSize: 13.5, - color: "#3F3F46", -}; - -const Field = ({ label, required, children }: { label: string; required?: boolean; children: React.ReactNode }) => ( - -); - const AgentToolkitWaitlistPage = () => { useSeo({ title: "Join the AI Agent Toolkit Waitlist · Fil One", - description: "Get early access to the AI Agent Toolkit. Connect your AI tools and automations to Fil One — join the waitlist and we'll reach out when your spot is ready.", + description: "Get early access to the AI Agent Toolkit. Connect your AI tools and automations to Fil One. Join the waitlist and we'll reach out when your spot is ready.", canonical: "https://www.fil.one/waitlist/ai-agent-toolkit", }); @@ -109,55 +75,42 @@ const AgentToolkitWaitlistPage = () => { setLoading(true); setError(null); - try { - const res = await fetch( - `https://api.hsforms.com/submissions/v3/integration/submit/${HS_PORTAL_ID}/${HS_AGENT_TOOLKIT_WAITLIST_FORM_GUID}`, - { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - fields: [ - { objectTypeId: "0-1", name: "email", value: email }, - { objectTypeId: "0-1", name: "firstname", value: firstName }, - { objectTypeId: "0-1", name: "lastname", value: lastName }, - ...(timeline ? [{ objectTypeId: "0-1", name: "ai_toolkit_timeline", value: timeline }] : []), - ...(teamSize ? [{ objectTypeId: "0-1", name: "team_size", value: teamSize }] : []), - ...(selectedTools.length > 0 ? [{ objectTypeId: "0-1", name: "ai_tools", value: selectedTools.join(";") }] : []), - ...(selectedTools.includes("Other") && otherTool ? [{ objectTypeId: "0-1", name: "other_tool", value: otherTool }] : []), - ...(notes ? [{ objectTypeId: "0-1", name: "ai_toolkit_notes", value: notes }] : []), - ], - context: getHubSpotContext("AI Agent Toolkit Waitlist"), - legalConsentOptions: { - consent: { - consentToProcess: true, - text: "By joining the waitlist, you consent to allow Fil One to store and process your information and send you product updates.", - communications: [{ - value: true, - subscriptionTypeId: HS_MARKETING_SUBSCRIPTION_TYPE_ID, - text: "I agree to receive product updates from Fil One.", - }], - }, - }, - }), - } - ); - if (!res.ok) { - const body = await res.json().catch(() => ({})); - const msg = body?.errors?.map((e: { message: string }) => e.message).join(" | ") || body?.message || JSON.stringify(body); - console.error("HubSpot submission error:", body); - setError(msg); - return; - } - setSubmitted(true); - } catch { - setError("Network error — please check your connection and try again."); - } finally { - setLoading(false); + const result = await submitHubSpotForm({ + formGuid: HS_AGENT_TOOLKIT_WAITLIST_FORM_GUID, + pageName: "AI Agent Toolkit Waitlist", + fields: [ + { objectTypeId: "0-1", name: "email", value: email }, + { objectTypeId: "0-1", name: "firstname", value: firstName }, + { objectTypeId: "0-1", name: "lastname", value: lastName }, + ...(timeline ? [{ objectTypeId: "0-1", name: "ai_toolkit_timeline", value: timeline }] : []), + ...(teamSize ? [{ objectTypeId: "0-1", name: "team_size", value: teamSize }] : []), + ...(selectedTools.length > 0 ? [{ objectTypeId: "0-1", name: "ai_tools", value: selectedTools.join(";") }] : []), + ...(selectedTools.includes("Other") && otherTool ? [{ objectTypeId: "0-1", name: "other_tool", value: otherTool }] : []), + ...(notes ? [{ objectTypeId: "0-1", name: "ai_toolkit_notes", value: notes }] : []), + ], + legalConsentOptions: { + consent: { + consentToProcess: true, + text: "By joining the waitlist, you consent to allow Fil One to store and process your information and send you product updates.", + communications: [{ + value: true, + subscriptionTypeId: HS_MARKETING_SUBSCRIPTION_TYPE_ID, + text: "I agree to receive product updates from Fil One.", + }], + }, + }, + }); + + setLoading(false); + if (!result.ok) { + setError(result.error); + return; } + setSubmitted(true); }; return ( -
+
@@ -167,126 +120,72 @@ const AgentToolkitWaitlistPage = () => { {/* Header */}
-

- Early access · AI Agent Toolkit -

-

+ Early access · AI Agent Toolkit +

Join the waitlist

-

- Get early access to the AI Agent Toolkit — connect your AI tools and automations directly to Fil One. We'll reach out as soon as your spot is ready. +

+ Get early access to the AI Agent Toolkit. Connect your AI tools and automations directly to Fil One, and we'll reach out as soon as your spot is ready.

-
+
{submitted ? ( -
-
- -
-

- You're on the list! -

-

- We'll reach out as soon as your spot is ready. Keep an eye on your inbox. -

-
+ + We'll reach out as soon as your spot is ready. Keep an eye on your inbox. + ) : (
- - setFirstName(e.target.value)} - placeholder="Jane" - required - style={inputStyle} - onFocus={e => (e.target.style.borderColor = "rgba(0,0,0,0.30)")} - onBlur={e => (e.target.style.borderColor = "rgba(0,0,0,0.10)")} - /> - - - setLastName(e.target.value)} - placeholder="Smith" - required - style={inputStyle} - onFocus={e => (e.target.style.borderColor = "rgba(0,0,0,0.30)")} - onBlur={e => (e.target.style.borderColor = "rgba(0,0,0,0.10)")} - /> - + setFirstName(e.target.value)} placeholder="Jane" /> + setLastName(e.target.value)} placeholder="Smith" />
- - setEmail(e.target.value)} - placeholder="you@company.com" - required - style={inputStyle} - onFocus={e => (e.target.style.borderColor = "rgba(0,0,0,0.30)")} - onBlur={e => (e.target.style.borderColor = "rgba(0,0,0,0.10)")} - /> - + setEmail(e.target.value)} placeholder="you@company.com" />
- - - - - - + setTimeline(e.target.value)}> + + {TIMELINES.map(o => )} + + setTeamSize(e.target.value)}> + + {TEAM_SIZES.map(o => )} +
-
- + {/* Tool picker: multi-select grid with a conditional "Other" input */} +
+ Which tools are you connecting?
- {TOOLS.map(tool => ( - - ))} + toggleTool(tool)} + className="peer sr-only" + /> + + {checked && } + + {tool} + + ); + })}
{selectedTools.includes("Other") && ( { onChange={e => setOtherTool(e.target.value)} placeholder="Which tool?" aria-label="Which tool?" - style={{ ...inputStyle, marginTop: 8 }} - onFocus={e => (e.target.style.borderColor = "rgba(0,0,0,0.30)")} - onBlur={e => (e.target.style.borderColor = "rgba(0,0,0,0.10)")} + className={`${FIELD_INPUT_CLASS} mt-2`} /> )}
- -