* 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
23 lines
819 B
TypeScript
23 lines
819 B
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { parseTopUpAmount } from "./HostedBillingContentUtils";
|
|
|
|
describe("parseTopUpAmount", () => {
|
|
it("accepts valid whole-dollar amounts", () => {
|
|
expect(parseTopUpAmount("20")).toEqual({ isValid: true, parsed: 20 });
|
|
expect(parseTopUpAmount("10")).toEqual({ isValid: true, parsed: 10 });
|
|
expect(parseTopUpAmount("99")).toEqual({ isValid: true, parsed: 99 });
|
|
});
|
|
|
|
it("rejects amounts below minimum", () => {
|
|
expect(parseTopUpAmount("9")).toEqual({ isValid: false, parsed: 20 });
|
|
});
|
|
|
|
it("rejects amounts above maximum", () => {
|
|
expect(parseTopUpAmount("100")).toEqual({ isValid: false, parsed: 20 });
|
|
});
|
|
|
|
it("rejects non-numeric input", () => {
|
|
expect(parseTopUpAmount("abc")).toEqual({ isValid: false, parsed: 20 });
|
|
});
|
|
});
|