diff --git a/src/ai/text/components/consume-credit-card.tsx b/src/ai/text/components/consume-credit-card.tsx index 478bf76..5ca5c27 100644 --- a/src/ai/text/components/consume-credit-card.tsx +++ b/src/ai/text/components/consume-credit-card.tsx @@ -2,7 +2,7 @@ import { CreditsBalanceButton } from '@/components/layout/credits-balance-button'; import { Button } from '@/components/ui/button'; -import { useCredits } from '@/hooks/use-credits'; +import { useConsumeCredits, useCreditBalance } from '@/hooks/use-credits-query'; import { CoinsIcon } from 'lucide-react'; import { useState } from 'react'; import { toast } from 'sonner'; @@ -10,24 +10,28 @@ import { toast } from 'sonner'; const CONSUME_CREDITS = 50; export function ConsumeCreditCard() { - const { consumeCredits, hasEnoughCredits, isLoading } = useCredits(); + const { data: balance = 0, isLoading: isLoadingBalance } = useCreditBalance(); + const consumeCreditsMutation = useConsumeCredits(); const [loading, setLoading] = useState(false); + const hasEnoughCredits = (amount: number) => balance >= amount; + const handleConsume = async () => { if (!hasEnoughCredits(CONSUME_CREDITS)) { toast.error('Insufficient credits, please buy more credits.'); return; } setLoading(true); - const success = await consumeCredits( - CONSUME_CREDITS, - `AI Text Credit Consumption (${CONSUME_CREDITS} credits)` - ); - setLoading(false); - if (success) { + try { + await consumeCreditsMutation.mutateAsync({ + amount: CONSUME_CREDITS, + description: `AI Text Credit Consumption (${CONSUME_CREDITS} credits)`, + }); toast.success(`${CONSUME_CREDITS} credits have been consumed.`); - } else { + } catch (error) { toast.error('Failed to consume credits, please try again later.'); + } finally { + setLoading(false); } }; @@ -40,7 +44,9 @@ export function ConsumeCreditCard() { variant="outline" size="sm" onClick={handleConsume} - disabled={isLoading || loading} + disabled={ + loading || isLoadingBalance || consumeCreditsMutation.isPending + } className="w-full cursor-pointer" > diff --git a/src/app/[locale]/providers.tsx b/src/app/[locale]/providers.tsx index c465d47..8f751af 100644 --- a/src/app/[locale]/providers.tsx +++ b/src/app/[locale]/providers.tsx @@ -1,7 +1,6 @@ 'use client'; import { ActiveThemeProvider } from '@/components/layout/active-theme-provider'; -import { CreditsProvider } from '@/components/layout/credits-provider'; import { PaymentProvider } from '@/components/layout/payment-provider'; import { QueryProvider } from '@/components/providers/query-provider'; import { TooltipProvider } from '@/components/ui/tooltip'; @@ -65,9 +64,7 @@ export function Providers({ children, locale }: ProvidersProps) { - - {children} - + {children} diff --git a/src/components/layout/credits-balance-button.tsx b/src/components/layout/credits-balance-button.tsx index bf4c677..16c3fda 100644 --- a/src/components/layout/credits-balance-button.tsx +++ b/src/components/layout/credits-balance-button.tsx @@ -2,7 +2,7 @@ import { Button } from '@/components/ui/button'; import { websiteConfig } from '@/config/website'; -import { useCredits } from '@/hooks/use-credits'; +import { useCreditBalance } from '@/hooks/use-credits-query'; import { useLocaleRouter } from '@/i18n/navigation'; import { Routes } from '@/routes'; import { CoinsIcon, Loader2Icon } from 'lucide-react'; @@ -15,8 +15,8 @@ export function CreditsBalanceButton() { const router = useLocaleRouter(); - // Use the new useCredits hook - const { balance, isLoading } = useCredits(); + // Use TanStack Query hook for credit balance + const { data: balance = 0, isLoading } = useCreditBalance(); const handleClick = () => { router.push(Routes.SettingsCredits); diff --git a/src/components/layout/credits-balance-menu.tsx b/src/components/layout/credits-balance-menu.tsx index 0155099..1e331e4 100644 --- a/src/components/layout/credits-balance-menu.tsx +++ b/src/components/layout/credits-balance-menu.tsx @@ -1,7 +1,7 @@ 'use client'; import { websiteConfig } from '@/config/website'; -import { useCredits } from '@/hooks/use-credits'; +import { useCreditBalance } from '@/hooks/use-credits-query'; import { useLocaleRouter } from '@/i18n/navigation'; import { Routes } from '@/routes'; import { CoinsIcon, Loader2Icon } from 'lucide-react'; @@ -16,8 +16,8 @@ export function CreditsBalanceMenu() { const t = useTranslations('Marketing.avatar'); const router = useLocaleRouter(); - // Use the new useCredits hook - const { balance, isLoading } = useCredits(); + // Use TanStack Query hook for credit balance + const { data: balance = 0, isLoading } = useCreditBalance(); const handleClick = () => { router.push(Routes.SettingsCredits); diff --git a/src/components/layout/credits-provider.tsx b/src/components/layout/credits-provider.tsx index 5fbed6e..975d435 100644 --- a/src/components/layout/credits-provider.tsx +++ b/src/components/layout/credits-provider.tsx @@ -1,31 +1,19 @@ 'use client'; import { websiteConfig } from '@/config/website'; -import { authClient } from '@/lib/auth-client'; -import { useCreditsStore } from '@/stores/credits-store'; -import { useEffect } from 'react'; /** * Credits Provider Component * - * This component initializes the credits store when the user is authenticated - * and handles cleanup when the user logs out. + * This component is now simplified since TanStack Query handles data fetching automatically. + * It's kept for potential future credits-related providers. * Only renders when credits are enabled in the website configuration. */ export function CreditsProvider({ children }: { children: React.ReactNode }) { - // Only initialize credits store if credits are enabled + // Only render when credits are enabled if (!websiteConfig.credits.enableCredits) { return <>{children}; } - const { fetchCredits } = useCreditsStore(); - const { data: session } = authClient.useSession(); - - useEffect(() => { - if (session?.user) { - fetchCredits(session.user); - } - }, [session?.user, fetchCredits]); - return <>{children}; } diff --git a/src/components/settings/credits/credit-transactions.tsx b/src/components/settings/credits/credit-transactions.tsx index 02629ed..9eea2ad 100644 --- a/src/components/settings/credits/credit-transactions.tsx +++ b/src/components/settings/credits/credit-transactions.tsx @@ -1,12 +1,10 @@ 'use client'; -import { getCreditTransactionsAction } from '@/actions/get-credit-transactions'; -import type { CreditTransaction } from '@/components/settings/credits/credit-transactions-table'; import { CreditTransactionsTable } from '@/components/settings/credits/credit-transactions-table'; +import { useCreditTransactions } from '@/hooks/use-credits-query'; import type { SortingState } from '@tanstack/react-table'; import { useTranslations } from 'next-intl'; -import { useCallback, useEffect, useState } from 'react'; -import { toast } from 'sonner'; +import { useState } from 'react'; /** * Credit transactions component @@ -16,57 +14,25 @@ export function CreditTransactions() { const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); const [search, setSearch] = useState(''); - const [data, setData] = useState([]); - const [total, setTotal] = useState(0); const [sorting, setSorting] = useState([ { id: 'createdAt', desc: true }, ]); - const [loading, setLoading] = useState(false); - const fetchData = useCallback(async () => { - setLoading(true); - try { - const result = await getCreditTransactionsAction({ - pageIndex, - pageSize, - search, - sorting, - }); - - if (result?.data?.success) { - setData(result.data.data?.items || []); - setTotal(result.data.data?.total || 0); - } else { - const errorMessage = result?.data?.error || t('error'); - toast.error(errorMessage); - setData([]); - setTotal(0); - } - } catch (error) { - console.error( - 'CreditTransactions, fetch credit transactions error:', - error - ); - toast.error(t('error')); - setData([]); - setTotal(0); - } finally { - setLoading(false); - } - }, [pageIndex, pageSize, search, sorting]); - - useEffect(() => { - fetchData(); - }, [fetchData]); + const { data, isLoading } = useCreditTransactions( + pageIndex, + pageSize, + search, + sorting + ); return ( (null); - const [isLoadingStats, setIsLoadingStats] = useState(true); - - // Fetch credit statistics - const fetchCreditStats = useCallback(async () => { - console.log('fetchCreditStats, fetch start'); - setIsLoadingStats(true); - try { - const result = await getCreditStatsAction(); - if (result?.data?.success && result.data.data) { - setCreditStats(result.data.data); - } else { - console.error('fetchCreditStats, failed to fetch credit stats', result); - } - } catch (error) { - console.error('fetchCreditStats, error:', error); - } finally { - setIsLoadingStats(false); - } - }, []); - - // Fetch stats on component mount - useEffect(() => { - fetchCreditStats(); - }, []); + // TanStack Query hook for credit statistics + const { + data: creditStats, + isLoading: isLoadingStats, + error: statsError, + refetch: refetchCreditStats, + } = useCreditStats(); // Check for payment success and show success message useEffect(() => { @@ -96,9 +69,9 @@ export default function CreditsBalanceCard() { toast.success(t('creditsAdded')); // Force refresh credits data to show updated balance - fetchCredits(true); + refetchCredits(); // Refresh credit stats - fetchCreditStats(); + refetchCreditStats(); }, 0); // Clean up URL parameters @@ -106,16 +79,16 @@ export default function CreditsBalanceCard() { url.searchParams.delete('credits_session_id'); localeRouter.replace(Routes.SettingsCredits + url.search); } - }, [searchParams, localeRouter, fetchCredits, fetchCreditStats, t]); + }, [searchParams, localeRouter, refetchCredits, refetchCreditStats, t]); // Retry all data fetching const handleRetry = useCallback(() => { // console.log('handleRetry, refetch credits data'); // Force refresh credits balance (ignore cache) - fetchCredits(true); + refetchCredits(); // Refresh credit stats - fetchCreditStats(); - }, [fetchCredits, fetchCreditStats]); + refetchCreditStats(); + }, [refetchCredits, refetchCreditStats]); // Render loading skeleton const isPageLoading = isLoadingBalance || isLoadingStats; @@ -140,7 +113,7 @@ export default function CreditsBalanceCard() { } // Render error state - if (error) { + if (error || statsError) { return ( @@ -148,7 +121,9 @@ export default function CreditsBalanceCard() { {t('description')} -
{error}
+
+ {error?.message || statsError?.message} +