import { Link, createFileRoute, useNavigate } from "@tanstack/react-router"; import { AutumnProvider, useCustomer } from "autumn-js/react"; import { useEffect, useState } from "react"; import { ArrowRight, Settings, User } from "lucide-react"; import { ThemePreferenceMenuItems } from "@/client/components/ThemePreferenceMenuItems"; import { captureClientEvent } from "@/client/lib/posthog"; import { getStoredRedditAttribution } from "@/client/lib/reddit-attribution"; import { signOutAndRedirect, useSession } from "@/lib/auth-client"; import { getStandardErrorMessage } from "@/client/lib/error-messages"; import { getSubscribeRouteState } from "@/client/features/billing/route-state"; import { getCustomerPlanStatus } from "@/client/features/billing/plan-detection"; import { AUTUMN_PAID_PLAN_ID } from "@/shared/billing"; import { captureRedditConversionEvent } from "@/serverFunctions/redditConversions"; export const Route = createFileRoute("/_authenticated/subscribe")({ validateSearch: (search: Record) => ({ upgrade: search.upgrade === true || search.upgrade === "true" ? true : undefined, }), component: SubscribePage, }); function SubscribePage() { return ( ); } function SubscribePageContent() { const navigate = useNavigate(); const { upgrade: isUpgradeFlow } = Route.useSearch(); const { data: session } = useSession(); const [isAttaching, setIsAttaching] = useState(false); const [error, setError] = useState(null); const checkoutCompleted = typeof window !== "undefined" && new URLSearchParams(window.location.search).get("checkout") === "success"; const customerQuery = useCustomer({ queryOptions: { enabled: Boolean(session?.user?.id), }, }); const planStatus = getCustomerPlanStatus(customerQuery.data); const subscribeRouteState = getSubscribeRouteState({ hasSession: Boolean(session?.user?.id), isCustomerLoading: customerQuery.isLoading, isCustomerError: customerQuery.isError, planStatus, }); useEffect(() => { if (subscribeRouteState === "redirectToApp") { if (checkoutCompleted) { captureClientEvent("billing:checkout_success"); const attribution = getStoredRedditAttribution(); if (attribution) { void captureRedditConversionEvent({ data: { attribution, eventType: "PURCHASE" }, }).finally(() => { void navigate({ to: "/", replace: true }); }); return; } } void navigate({ to: "/", replace: true }); } }, [checkoutCompleted, navigate, subscribeRouteState]); if ( subscribeRouteState === "loading" || subscribeRouteState === "redirectToApp" ) { return null; } if (subscribeRouteState === "error") { return (
OpenSEO

Billing unavailable

{getStandardErrorMessage( customerQuery.error, "We couldn't verify your billing status right now. Please try again.", )}

); } async function handleSubscribe() { setError(null); setIsAttaching(true); try { captureClientEvent("billing:checkout_start"); await customerQuery.attach({ planId: AUTUMN_PAID_PLAN_ID, redirectMode: "always", successUrl: `${window.location.origin}${window.location.pathname}?checkout=success`, }); } catch (err) { setError( getStandardErrorMessage( err, "We couldn't start the checkout. Please try again.", ), ); setIsAttaching(false); } } const firstName = session?.user?.name?.split(" ")[0] || ""; return (
OpenSEO

{isUpgradeFlow ? "Upgrade your plan" : firstName ? `Welcome to OpenSEO, ${firstName}!` : "Welcome to OpenSEO!"}

SEO on your terms. All your SEO tools in one place at a fair price.

Base Plan $10/month
    {[ "Access to all OpenSEO features", "Do keyword research, backlink analysis and site audits", "Includes $10.00 of Usage Credits each month", ].map((item) => (
  • {item}
  • ))}
{error ?

{error}

: null}

Cancel anytime — no commitment. Powered by Stripe.

{isUpgradeFlow ? ( ) : ( <>

Or try it free — you have $0.50 of credits to explore before committing.

)}
); } function SubscribePageAccountMenu({ email }: { email: string | undefined }) { if (!email) return null; const handleSignOut = () => signOutAndRedirect(); return (
  • {email}
  • Settings
); }