metatron-open-seo/src/routes/_authenticated.tsx
Ben Senescu 570b995248 Refactor billing + onboarding (#61)
* fix: use full page reload after email verification

Client-side navigation via TanStack Router during the auth→app
transition can race with Vite HMR, causing "action is not a function"
server function errors.

* feat: add minimal /subscribe onboarding page

New post-auth subscribe page at /subscribe using the same centered
layout as auth pages. Shows plan details and a single Subscribe CTA.
Redirects PAYMENT_REQUIRED users here instead of /billing.

* redesign: rewrite billing page with usage chart and cleaner layout

Delete the sprawling multi-component billing page and replace it with a
single-file implementation. Two cards sit side by side at the top
(subscription summary + buy credits), with a 30-day usage bar chart
below powered by Autumn's useAggregateEvents hook and recharts.

Removed BillingRouteParts.tsx, HostedBillingContent.tsx, and trimmed
HostedBillingContentUtils to only parseTopUpAmount.

* polish: billing page improvements and OpenSEO nav link

- Two-column layout with subscription summary and buy credits side by side
- Usage bar chart using ResizeObserver instead of ResponsiveContainer
- Input validation with inline error message
- Full-page redirect state when navigating to Stripe
- Make OpenSEO logo in navbar link to /

* fix: guard app routes and include top-up usage

* fix: restore billing onboarding guards

Keep unpaid orgs on /subscribe and avoid misleading billing states when Autumn customer lookups fail.

* fix: split billing usage chart for ci checks
2026-04-08 14:09:01 -04:00

36 lines
994 B
TypeScript

import { Outlet, createFileRoute, useNavigate } from "@tanstack/react-router";
import { useEffect } from "react";
import { AuthPageShell } from "@/client/features/auth/AuthPage";
import { useSession } from "@/lib/auth-client";
import { isHostedClientAuthMode } from "@/lib/auth-mode";
export const Route = createFileRoute("/_authenticated")({
component: AuthenticatedShellLayout,
});
function AuthenticatedShellLayout() {
const navigate = useNavigate();
const { data: session, isPending } = useSession();
const isHostedMode = isHostedClientAuthMode();
useEffect(() => {
if (isPending || !isHostedMode) return;
if (!session?.user?.id) {
void navigate({
to: "/sign-in",
search: { redirect: window.location.pathname },
});
}
}, [isPending, isHostedMode, session?.user?.id, navigate]);
if (!isHostedMode || isPending || !session?.user?.id) {
return null;
}
return (
<AuthPageShell>
<Outlet />
</AuthPageShell>
);
}