/** * BoostMedia AI Content Generator Admin - Credits & Pricing Hooks * * @package BoostMedia_AI * @license GPL-2.0-or-later */ import { useState, useEffect, useCallback, useRef } from 'react' import { endpoints, getErrorMessage } from '../api/client' export interface CreditBucket { total: number used: number remaining: number } export interface CreditsStatus { allowed: boolean site_status?: string boost_credits: CreditBucket daily_usage?: { generated_today?: number limit?: number remaining?: number articles_generated?: number article_limit?: number articles_remaining?: number } credits?: { free?: CreditBucket subscription?: CreditBucket & { renew_at: string | null; status: string } purchased?: CreditBucket } } export interface PricingPackage { id: string name: string price: number credits: number popular: boolean } export interface PricingSubscription { id: string name: string price: number allowance: number popular: boolean } export interface PricingCatalog { currency: string packages: PricingPackage[] subscriptions: PricingSubscription[] } export function useCreditsStatus() { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [refreshing, setRefreshing] = useState(false) const [error, setError] = useState(null) const dataRef = useRef(null) const fetch = useCallback(async () => { if (dataRef.current) { setRefreshing(true) } else { setLoading(true) } setError(null) try { const res = await endpoints.getCreditsStatus() const result = res.data as CreditsStatus setData(result) dataRef.current = result } catch (err) { setError(getErrorMessage(err, 'Failed to load credits')) } finally { setLoading(false) setRefreshing(false) } }, []) useEffect(() => { fetch() }, [fetch]) return { data, loading, refreshing, error, refetch: fetch } } export function usePricingCatalog() { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const fetch = useCallback(async () => { setLoading(true) try { const res = await endpoints.getPricingCatalog() setData(res.data as PricingCatalog) } catch (err) { setError(getErrorMessage(err, 'Failed to load pricing')) } finally { setLoading(false) } }, []) useEffect(() => { fetch() }, [fetch]) return { data, loading, error } } export interface SubscriptionStatus { status: string allowance_total: number allowance_used: number renew_at: string | null } export function useSubscriptionStatus() { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const fetch = useCallback(async () => { setLoading(true) setError(null) try { const res = await endpoints.getSubscriptionStatus() setData(res.data as SubscriptionStatus) } catch (err) { setError(getErrorMessage(err, 'Failed to load subscription status')) } finally { setLoading(false) } }, []) useEffect(() => { fetch() }, [fetch]) return { data, loading, error, refetch: fetch } } export function useCancelSubscription() { const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const cancel = useCallback(async (): Promise => { setLoading(true) setError(null) try { await endpoints.cancelSubscription() return true } catch (err) { const msg = getErrorMessage(err, 'Failed to cancel subscription') setError(msg) return false } finally { setLoading(false) } }, []) return { cancel, loading, error } } export function useCreateSubscription() { const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const create = useCallback(async (packageId: string): Promise<{ approval_url?: string; subscription_id?: string } | null> => { setLoading(true) setError(null) try { const res = await endpoints.createSubscription(packageId) return res.data as { approval_url?: string; subscription_id?: string } } catch (err) { const msg = getErrorMessage(err, 'Failed to create subscription') setError(msg) return null } finally { setLoading(false) } }, []) return { create, loading, error } }