import { useEffect, useRef, useState } from "react"; import { Link } from "react-router-dom"; import type { BillingCycle } from "../api/endpoints"; import type { Meter, PlanInfo } from "../api/types"; import { useUpgrade } from "../hooks/useUpgrade"; import { CheckIcon } from "./icons/Icons"; import { annualMonthly, annualTotal, money } from "./PricingTiers"; const ORDER = ["free", "writer", "studio"]; const LIMIT_TITLES: Record = { audio_minutes: "Out of audio fuel", videos: "Out of videos", launch_kits: "Launch Kits used up", audio_overviews: "Audio overview used up", indexed_posts: "Post limit reached", reports: "Reports used up", infographics: "Infographics used up", sources: "Your station is full", voice_cloning: "Voice cloning is locked", }; /** What the plan adds over the current one, as short boost chips ("20x audio minutes"). */ function boosts(plan: PlanInfo, current: PlanInfo): string[] { const out: string[] = []; const times = (a: number, b: number, label: string) => { if (a < 0 && b >= 0) out.push(`Unlimited ${label}`); else if (b > 0 && a > b) out.push(`${Math.round(a / b)}x ${label}`); }; if (plan.indexed_posts > current.indexed_posts) out.push(`${plan.indexed_posts} indexed posts`); if (current.audio_overviews >= 0 && plan.audio_overviews < 0) out.push(`${plan.audio_minutes} min of audio a month`); times(plan.audio_minutes, current.audio_minutes, "audio minutes"); times(plan.videos, current.videos, "videos"); times(plan.launch_kits, current.launch_kits, "Launch Kits"); times(plan.reports, current.reports, "reports"); times(plan.infographics, current.infographics, "infographics"); if (plan.voice_cloning && !current.voice_cloning) out.push("Voice cloning"); return out; } function resetDate(since: string | undefined, videosResetAt?: string | null): string { if (videosResetAt) return new Date(videosResetAt).toLocaleDateString(undefined, { month: "long", day: "numeric" }); const d = since ? new Date(since) : new Date(); const next = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 1)); return next.toLocaleDateString(undefined, { month: "long", day: "numeric" }); } function Scene({ mode }: { mode: "explore" | "limit" | "welcome" }) { return (