From a07807b8846f7bfe4c60c6276f26ec92624460ff Mon Sep 17 00:00:00 2001 From: Emil F Date: Tue, 31 Mar 2026 20:06:14 +0300 Subject: [PATCH] fix(frontend): gate credits API calls behind buyCredits feature flag The backend returns 404 for /credits/summary and /credits/batches/expiring when BUY_CREDITS_ACTIVE is disabled. SessionEnsurer was polling /credits/summary every 30 s and ExpiryWarningBanner was polling /credits/batches/expiring every 5 min for all authenticated users, flooding the console with 404 errors and adding unnecessary network overhead. Both queries now use `enabled: !!session?.data && !!features?.buyCredits` so they only fire when the feature flag is actually on. ExpiryWarningBanner also gains the useUserStore import needed to read the flag. Co-Authored-By: Claude Sonnet 4.6 --- apps/frontend/src/components/atoms/ExpiryWarningBanner.tsx | 6 +++++- apps/frontend/src/components/atoms/SessionEnsurer.tsx | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/components/atoms/ExpiryWarningBanner.tsx b/apps/frontend/src/components/atoms/ExpiryWarningBanner.tsx index 13cf90348..1bc780726 100644 --- a/apps/frontend/src/components/atoms/ExpiryWarningBanner.tsx +++ b/apps/frontend/src/components/atoms/ExpiryWarningBanner.tsx @@ -11,6 +11,7 @@ import { sumExpiringUploadBytes, } from '../../utils/credits'; import { BannerShell } from '../organisms/BannerNotifications/BannerShell'; +import { useUserStore } from '../../globalStates/user'; /** * Displays a warning banner when the user has purchased credits that will @@ -20,13 +21,16 @@ import { BannerShell } from '../organisms/BannerNotifications/BannerShell'; export const ExpiryWarningBanner = () => { const { api } = useNetwork(); const session = useContext(SessionContext); + const features = useUserStore((m) => m.features); const { data: expiringBatches } = useQuery({ queryKey: ['expiringCreditBatches'], queryFn: () => api.getExpiringCreditBatches(), // Refresh every 5 minutes – expiry warnings don't need to be real-time refetchInterval: 5 * 60 * 1000, - enabled: !!session?.data, + // Only fetch when the buyCredits feature flag is enabled – the backend + // returns 404 for these endpoints when the flag is off. + enabled: !!session?.data && !!features?.buyCredits, }); if (!expiringBatches || expiringBatches.length === 0) return null; diff --git a/apps/frontend/src/components/atoms/SessionEnsurer.tsx b/apps/frontend/src/components/atoms/SessionEnsurer.tsx index 86692fd9a..675e9bf29 100644 --- a/apps/frontend/src/components/atoms/SessionEnsurer.tsx +++ b/apps/frontend/src/components/atoms/SessionEnsurer.tsx @@ -61,7 +61,9 @@ export const SessionEnsurer = ({ children }: { children: React.ReactNode }) => { queryFn: () => api.getCreditSummary(), // Refresh every 30 s so the cap / balance stays reasonably fresh refetchInterval: 30_000, - enabled: !!session?.data, + // Only fetch when the buyCredits feature flag is enabled – the backend + // returns 404 for these endpoints when the flag is off. + enabled: !!session?.data && !!features?.buyCredits, }); const { data: touStatusData, isLoading: touStatusLoading } = useQuery({