refactor: enhance credit balance and stats hooks with improved error handling and logging
This commit is contained in:
parent
13c23dab56
commit
1fb89a2a05
@ -15,8 +15,8 @@ export function QueryProvider({ children }: QueryProviderProps) {
|
||||
new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime)
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes - default stale time
|
||||
gcTime: 10 * 60 * 1000, // 10 minutes - default garbage collection time
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
|
@ -11,7 +11,11 @@ import {
|
||||
} from '@/components/ui/card';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { websiteConfig } from '@/config/website';
|
||||
import { useCreditBalance, useCreditStats } from '@/hooks/use-credits';
|
||||
import {
|
||||
creditsKeys,
|
||||
useCreditBalance,
|
||||
useCreditStats,
|
||||
} from '@/hooks/use-credits';
|
||||
import { useMounted } from '@/hooks/use-mounted';
|
||||
import { useCurrentPlan } from '@/hooks/use-payment';
|
||||
import { useLocaleRouter } from '@/i18n/navigation';
|
||||
@ -19,6 +23,7 @@ import { authClient } from '@/lib/auth-client';
|
||||
import { formatDate } from '@/lib/formatter';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Routes } from '@/routes';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { RefreshCwIcon } from 'lucide-react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
@ -37,6 +42,7 @@ export default function CreditsBalanceCard() {
|
||||
const t = useTranslations('Dashboard.settings.credits.balance');
|
||||
const searchParams = useSearchParams();
|
||||
const localeRouter = useLocaleRouter();
|
||||
const queryClient = useQueryClient();
|
||||
const hasHandledSession = useRef(false);
|
||||
const mounted = useMounted();
|
||||
|
||||
@ -44,8 +50,8 @@ export default function CreditsBalanceCard() {
|
||||
const {
|
||||
data: balance = 0,
|
||||
isLoading: isLoadingBalance,
|
||||
error,
|
||||
refetch: refetchCredits,
|
||||
error: balanceError,
|
||||
refetch: refetchBalance,
|
||||
} = useCreditBalance();
|
||||
|
||||
// Get payment info to check plan type
|
||||
@ -58,7 +64,7 @@ export default function CreditsBalanceCard() {
|
||||
data: creditStats,
|
||||
isLoading: isLoadingStats,
|
||||
error: statsError,
|
||||
refetch: refetchCreditStats,
|
||||
refetch: refetchStats,
|
||||
} = useCreditStats();
|
||||
|
||||
// Check for payment success and show success message
|
||||
@ -67,35 +73,48 @@ export default function CreditsBalanceCard() {
|
||||
if (sessionId && !hasHandledSession.current) {
|
||||
hasHandledSession.current = true;
|
||||
|
||||
setTimeout(() => {
|
||||
// Show success toast and refresh data after payment
|
||||
toast.success(t('creditsAdded'));
|
||||
|
||||
// Force refresh credits data to show updated balance
|
||||
refetchCredits();
|
||||
// Refresh credit stats
|
||||
refetchCreditStats();
|
||||
}, 0);
|
||||
|
||||
// Clean up URL parameters
|
||||
// Clean up URL parameters first
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.delete('credits_session_id');
|
||||
localeRouter.replace(Routes.SettingsCredits + url.search);
|
||||
|
||||
// Handle payment success with proper timing
|
||||
const handlePaymentSuccess = async () => {
|
||||
// Show success toast (must be in setTimeout to avoid errors)
|
||||
setTimeout(() => {
|
||||
toast.success(t('creditsAdded'));
|
||||
}, 0);
|
||||
|
||||
// Wait for webhook to process
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
// Force refresh data
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: creditsKeys.balance(),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: creditsKeys.stats(),
|
||||
});
|
||||
};
|
||||
|
||||
handlePaymentSuccess();
|
||||
}
|
||||
}, [searchParams, localeRouter, refetchCredits, refetchCreditStats, t]);
|
||||
}, [searchParams, localeRouter, queryClient, t]);
|
||||
|
||||
// Retry all data fetching
|
||||
const handleRetry = useCallback(() => {
|
||||
// console.log('handleRetry, refetch credits data');
|
||||
// Force refresh credits balance (ignore cache)
|
||||
refetchCredits();
|
||||
// Refresh credit stats
|
||||
refetchCreditStats();
|
||||
}, [refetchCredits, refetchCreditStats]);
|
||||
// Force invalidate cache to ensure fresh data
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: creditsKeys.balance(),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: creditsKeys.stats(),
|
||||
});
|
||||
}, [queryClient]);
|
||||
|
||||
// Render loading skeleton
|
||||
const isPageLoading = isLoadingBalance || isLoadingStats;
|
||||
if (!mounted || isPageLoading) {
|
||||
if (!mounted || isLoadingBalance || isLoadingStats) {
|
||||
return (
|
||||
<Card className={cn('w-full overflow-hidden pt-6 pb-0 flex flex-col')}>
|
||||
<CardHeader>
|
||||
@ -116,7 +135,7 @@ export default function CreditsBalanceCard() {
|
||||
}
|
||||
|
||||
// Render error state
|
||||
if (error || statsError) {
|
||||
if (balanceError || statsError) {
|
||||
return (
|
||||
<Card className={cn('w-full overflow-hidden pt-6 pb-0 flex flex-col')}>
|
||||
<CardHeader>
|
||||
@ -125,7 +144,7 @@ export default function CreditsBalanceCard() {
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4 flex-1">
|
||||
<div className="text-destructive text-sm">
|
||||
{error?.message || statsError?.message}
|
||||
{balanceError?.message || statsError?.message}
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="mt-2 px-6 py-4 flex justify-end items-center bg-background rounded-none">
|
||||
|
@ -19,31 +19,39 @@ export const creditsKeys = {
|
||||
}) => [...creditsKeys.transactions(), filters] as const,
|
||||
};
|
||||
|
||||
// Hook to fetch credit statistics
|
||||
export function useCreditStats() {
|
||||
return useQuery({
|
||||
queryKey: creditsKeys.stats(),
|
||||
queryFn: async () => {
|
||||
const result = await getCreditStatsAction();
|
||||
if (!result?.data?.success) {
|
||||
throw new Error(result?.data?.error || 'Failed to fetch credit stats');
|
||||
}
|
||||
return result.data.data;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Hook to fetch credit balance
|
||||
export function useCreditBalance() {
|
||||
return useQuery({
|
||||
queryKey: creditsKeys.balance(),
|
||||
queryFn: async () => {
|
||||
console.log('Fetching credit balance...');
|
||||
const result = await getCreditBalanceAction();
|
||||
if (!result?.data?.success) {
|
||||
throw new Error('Failed to fetch credit balance');
|
||||
}
|
||||
console.log('Credit balance fetched:', result.data.credits);
|
||||
return result.data.credits || 0;
|
||||
},
|
||||
staleTime: 30 * 1000, // 30 seconds - reasonable stale time
|
||||
retry: 2, // Retry up to 2 times on failure
|
||||
});
|
||||
}
|
||||
|
||||
// Hook to fetch credit statistics
|
||||
export function useCreditStats() {
|
||||
return useQuery({
|
||||
queryKey: creditsKeys.stats(),
|
||||
queryFn: async () => {
|
||||
console.log('Fetching credit stats...');
|
||||
const result = await getCreditStatsAction();
|
||||
if (!result?.data?.success) {
|
||||
throw new Error(result?.data?.error || 'Failed to fetch credit stats');
|
||||
}
|
||||
console.log('Credit stats fetched:', result.data.data);
|
||||
return result.data.data;
|
||||
},
|
||||
staleTime: 30 * 1000, // 30 seconds - reasonable stale time
|
||||
retry: 2, // Retry up to 2 times on failure
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
import { QueryClient } from '@tanstack/react-query';
|
||||
|
||||
export const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime)
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false,
|
||||
},
|
||||
mutations: {
|
||||
retry: 1,
|
||||
},
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue
Block a user