"use client" import { useEffect, useRef, useState } from "react" import { useMutation, useQueryClient } from "@tanstack/react-query" import { useSearchParams } from "next/navigation" import { useUserProfile } from "@/lib/queries/use-user-profile" import { queryKeys } from "@/lib/queries/query-keys" import { TIER_LIMITS } from "@asa-news/shared" import { classNames } from "@/lib/utilities" import { notify } from "@/lib/notify" function useCreateCheckoutSession() { return useMutation({ mutationFn: async ({ billingInterval, targetTier, }: { billingInterval: "monthly" | "yearly" targetTier: "pro" | "developer" }) => { const response = await fetch("/api/billing/create-checkout-session", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ billingInterval, targetTier }), }) if (!response.ok) { const data = await response.json() throw new Error(data.error || "failed to create checkout session") } const data = await response.json() return data as { url?: string; upgraded?: boolean } }, }) } function useCreatePortalSession() { return useMutation({ mutationFn: async () => { const response = await fetch("/api/billing/create-portal-session", { method: "POST", }) if (!response.ok) { const data = await response.json() throw new Error(data.error || "failed to create portal session") } const data = await response.json() return data as { url: string } }, }) } const PRO_FEATURES = [ `${TIER_LIMITS.pro.maximumFeeds} feeds`, `${TIER_LIMITS.pro.historyRetentionDays}-day history retention`, `${TIER_LIMITS.pro.refreshIntervalSeconds / 60}-minute refresh interval`, "authenticated feeds", "opml export", "manual feed refresh", ] const DEVELOPER_FEATURES = [ `${TIER_LIMITS.developer.maximumFeeds} feeds`, "everything in pro", "read-only rest api", "webhook push notifications", ] function UpgradeCard({ targetTier, features, monthlyPrice, yearlyPrice, }: { targetTier: "pro" | "developer" features: string[] monthlyPrice: string yearlyPrice: string }) { const [billingInterval, setBillingInterval] = useState< "monthly" | "yearly" >("yearly") const queryClient = useQueryClient() const createCheckoutSession = useCreateCheckoutSession() function handleUpgrade() { createCheckoutSession.mutate( { billingInterval, targetTier }, { onSuccess: (data) => { if (data.upgraded) { queryClient.invalidateQueries({ queryKey: queryKeys.userProfile.all, }) notify(`upgraded to ${targetTier}!`) } else if (data.url) { window.location.href = data.url } }, onError: (error: Error) => { notify("failed to start checkout: " + error.message) }, } ) } return (
loading billing ...
} if (!userProfile) { returnfailed to load billing
} function handleManageSubscription() { createPortalSession.mutate(undefined, { onSuccess: (data) => { window.location.href = data.url }, onError: (error: Error) => { notify("failed to open billing portal: " + error.message) }, }) } const isPaidTier = userProfile.tier === "pro" || userProfile.tier === "developer" const isCancelling = userProfile.stripeSubscriptionStatus === "active" && isPaidTier && userProfile.stripeCurrentPeriodEnd !== null return (your pro plan is active until{" "} {new Date( userProfile.stripeCurrentPeriodEnd ).toLocaleDateString()}
)} {userProfile.stripeSubscriptionStatus === "past_due" && (payment failed — please update your payment method
)}your developer plan is active until{" "} {new Date( userProfile.stripeCurrentPeriodEnd ).toLocaleDateString()}
)} {userProfile.stripeSubscriptionStatus === "past_due" && (payment failed — please update your payment method
)}