"use client";
import { CheckIcon, CirclePauseIcon, ClockIcon, GaugeIcon, SparklesIcon } from "lucide-react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
import { useEffect, useRef, useState } from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
export interface LimitReachedUpgrade {
plan: string;
limit: number;
}
export interface LimitReachedProps {
used?: number;
limit?: number;
unit?: string;
shortUnit?: string;
period?: string;
planName?: string;
secondsUntilReset?: number;
resetDate?: string;
upgrade?: LimitReachedUpgrade | null;
stillWorks?: string[];
paused?: string[];
upgrading?: boolean;
secondaryLabel?: string;
secondaryDoneLabel?: string;
onUpgrade?: () => void;
onSecondary?: () => void;
onReset?: () => void;
className?: string;
}
const meterSpring = { type: "spring", stiffness: 110, damping: 17 } as const;
const roll = { type: "spring", stiffness: 320, damping: 32 } as const;
const glide = { type: "spring", stiffness: 380, damping: 34 } as const;
// Stays false until mounted so the server render and the first client render match.
function useSafeReducedMotion() {
const prefers = useReducedMotion();
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
return mounted && !!prefers;
}
const format = (n: number) => n.toLocaleString("en-US");
const pad = (n: number) => String(n).padStart(2, "0");
function split(seconds: number) {
const s = Math.max(0, Math.floor(seconds));
return { d: Math.floor(s / 86400), h: Math.floor((s % 86400) / 3600), m: Math.floor((s % 3600) / 60), s: s % 60 };
}
function spoken(seconds: number) {
const t = split(seconds);
const parts = [
t.d && `${t.d} ${t.d === 1 ? "day" : "days"}`,
t.h && `${t.h} ${t.h === 1 ? "hour" : "hours"}`,
!t.d && t.m && `${t.m} min`,
].filter(Boolean);
return parts.length ? parts.join(" ") : "less than a minute";
}
function Roll({ text, reduce, className }: { text: string; reduce: boolean; className?: string }) {
const chars = text.split("");
return (
{chars.map((char, i) => {
const key = chars.length - i;
if (!/\d/.test(char)) return {char};
return (
{char}
{atLimit
? `AI features are paused until your ${planName} plan resets. Everything else works as usual.`
: "Paused features are back on."}
{atLimit ? `You've used all ${format(limit)} ${unit} ${period}` : `${format(limit - used)} ${unit} left ${period}`}