web-production-saas-starter/next_b2b_starter/lib/hooks/queries/use-subscription-query.ts
2025-12-16 18:54:41 +04:00

79 lines
1.8 KiB
TypeScript

/**
* Subscription Query Hook
*
* Fetches and caches the current subscription status from Polar.
* Uses the client-side API endpoint instead of server-side resolver.
*/
import { useQuery, type UseQueryOptions } from "@tanstack/react-query";
import { queryKeys } from "./query-keys";
import type { SubscriptionGateState } from "@/lib/polar/current-subscription";
async function fetchSubscriptionStatus(): Promise<SubscriptionGateState> {
const response = await fetch("/api/billing/status", {
method: "GET",
credentials: "include",
headers: {
Accept: "application/json",
},
});
if (!response.ok) {
let errorMessage = `Unable to load subscription status (HTTP ${response.status})`;
try {
const payload = await response.json();
if (payload?.error && typeof payload.error === "string") {
errorMessage = payload.error;
}
} catch {
// Ignore JSON parsing errors
}
throw new Error(errorMessage);
}
return response.json();
}
export function useSubscriptionQuery(
options?: Omit<
UseQueryOptions<SubscriptionGateState, Error>,
"queryKey" | "queryFn"
>
) {
return useQuery({
queryKey: queryKeys.subscription.status(),
queryFn: fetchSubscriptionStatus,
// Subscription status is fresh for 5 minutes
staleTime: 5 * 60 * 1000,
// Cache for 15 minutes
gcTime: 15 * 60 * 1000,
// Retry once on failure
retry: 1,
// Don't refetch on window focus
refetchOnWindowFocus: false,
...options,
});
}
/**
* Hook to get subscription state with safe defaults
*/
export function useSubscription() {
const { data } = useSubscriptionQuery();
return data ?? null;
}
/**
* Hook to check if subscription is active
*/
export function useIsSubscriptionActive() {
const subscription = useSubscription();
return subscription?.isActive ?? false;
}