diff --git a/build.gradle b/build.gradle index 1b48160810..ddfbb58b99 100644 --- a/build.gradle +++ b/build.gradle @@ -78,7 +78,7 @@ springBoot { allprojects { group = 'stirling.software' - version = '2.7.1' + version = '2.7.2' configurations.configureEach { exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat" diff --git a/frontend/src/desktop/components/shared/modals/CreditModalBootstrap.tsx b/frontend/src/desktop/components/shared/modals/CreditModalBootstrap.tsx index 0c2f3a7f68..2f3c456ae2 100644 --- a/frontend/src/desktop/components/shared/modals/CreditModalBootstrap.tsx +++ b/frontend/src/desktop/components/shared/modals/CreditModalBootstrap.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; import { useSaaSBilling } from '@app/contexts/SaasBillingContext'; +import { useSaaSMode } from '@app/hooks/useSaaSMode'; import { BILLING_CONFIG } from '@app/config/billing'; import { CreditExhaustedModal } from '@app/components/shared/modals/CreditExhaustedModal'; import { InsufficientCreditsModal } from '@app/components/shared/modals/InsufficientCreditsModal'; @@ -19,16 +20,17 @@ export function CreditModalBootstrap() { requiredCredits?: number; }>({}); + const isSaaSMode = useSaaSMode(); const { creditBalance, isManagedTeamMember, lastFetchTime, plansLastFetchTime, refreshPlans } = useSaaSBilling(); // Preload plan pricing when billing confirms credits are low. - // Fires once: only when billing has loaded (lastFetchTime set) and plans haven't been + // Fires once: only when in SaaS mode, billing has loaded (lastFetchTime set) and plans haven't been // fetched yet (plansLastFetchTime null). This way the modal shows real prices instantly. useEffect(() => { - if (lastFetchTime !== null && plansLastFetchTime === null && creditBalance < BILLING_CONFIG.PLAN_PRICING_PRELOAD_THRESHOLD && !isManagedTeamMember) { + if (isSaaSMode && lastFetchTime !== null && plansLastFetchTime === null && creditBalance < BILLING_CONFIG.PLAN_PRICING_PRELOAD_THRESHOLD && !isManagedTeamMember) { refreshPlans(); } - }, [lastFetchTime, plansLastFetchTime, creditBalance, isManagedTeamMember, refreshPlans]); + }, [isSaaSMode, lastFetchTime, plansLastFetchTime, creditBalance, isManagedTeamMember, refreshPlans]); // Monitor credit balance and dispatch events useCreditEvents(); diff --git a/frontend/src/desktop/hooks/useCreditCheck.ts b/frontend/src/desktop/hooks/useCreditCheck.ts index 4a387eaf6f..17178ad99a 100644 --- a/frontend/src/desktop/hooks/useCreditCheck.ts +++ b/frontend/src/desktop/hooks/useCreditCheck.ts @@ -1,6 +1,7 @@ import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { useSaaSBilling } from '@app/contexts/SaasBillingContext'; +import { useSaaSMode } from '@app/hooks/useSaaSMode'; import { getToolCreditCost } from '@app/utils/creditCosts'; import { CREDIT_EVENTS } from '@app/constants/creditEvents'; import type { ToolId } from '@app/types/toolId'; @@ -16,9 +17,11 @@ import type { ToolId } from '@app/types/toolId'; */ export function useCreditCheck(operationType?: string) { const billing = useSaaSBilling(); + const isSaaSMode = useSaaSMode(); const { t } = useTranslation(); const checkCredits = useCallback(async (): Promise => { + if (!isSaaSMode) return null; // Credits only apply in SaaS mode, not self-hosted if (!billing) return null; const { creditBalance, loading } = billing; @@ -41,7 +44,7 @@ export function useCreditCheck(operationType?: string) { } return null; - }, [billing, operationType, t]); + }, [billing, isSaaSMode, operationType, t]); return { checkCredits }; } diff --git a/frontend/src/desktop/hooks/useCreditEvents.ts b/frontend/src/desktop/hooks/useCreditEvents.ts index c587c3309a..1e05cb61a4 100644 --- a/frontend/src/desktop/hooks/useCreditEvents.ts +++ b/frontend/src/desktop/hooks/useCreditEvents.ts @@ -1,20 +1,24 @@ import { useEffect, useRef } from 'react'; import { useSaaSBilling } from '@app/contexts/SaasBillingContext'; +import { useSaaSMode } from '@app/hooks/useSaaSMode'; import { CREDIT_EVENTS } from '@app/constants/creditEvents'; /** * Desktop hook that monitors credit balance and dispatches events - * when credits are exhausted or low + * when credits are exhausted or low. + * Only active in SaaS mode — self-hosted users have no credit balance. */ export function useCreditEvents() { + const isSaaSMode = useSaaSMode(); const { creditBalance } = useSaaSBilling(); const prevBalanceRef = useRef(creditBalance); useEffect(() => { const prevBalance = prevBalanceRef.current; - // Dispatch exhausted event when credits reach 0 from positive balance - if (creditBalance <= 0 && prevBalance > 0) { + // Dispatch exhausted event when credits reach 0 from positive balance. + // Skip entirely in self-hosted mode — creditBalance defaults to 0 there. + if (isSaaSMode && creditBalance <= 0 && prevBalance > 0) { window.dispatchEvent( new CustomEvent(CREDIT_EVENTS.EXHAUSTED, { detail: { previousBalance: prevBalance, currentBalance: creditBalance }, @@ -24,5 +28,5 @@ export function useCreditEvents() { // Update ref for next comparison prevBalanceRef.current = creditBalance; - }, [creditBalance]); + }, [isSaaSMode, creditBalance]); }