diff --git a/frontend/src/components/AccountMenu.tsx b/frontend/src/components/AccountMenu.tsx index 5f8c0e75..03ffb22e 100644 --- a/frontend/src/components/AccountMenu.tsx +++ b/frontend/src/components/AccountMenu.tsx @@ -49,6 +49,7 @@ import { Link } from "@tanstack/react-router"; import { getBillingService } from "@/billing/billingService"; import { useState } from "react"; import type { TeamStatus } from "@/types/team"; +import { Alert, AlertDescription } from "@/components/ui/alert"; import { TeamManagementDialog } from "@/components/team/TeamManagementDialog"; import { ApiKeyManagementDialog } from "@/components/apikeys/ApiKeyManagementDialog"; import packageJson from "../../package.json"; @@ -110,6 +111,7 @@ export function AccountMenu() { const [isTeamDialogOpen, setIsTeamDialogOpen] = useState(false); const [isApiKeyDialogOpen, setIsApiKeyDialogOpen] = useState(false); const [showAboutMenu, setShowAboutMenu] = useState(false); + const [portalError, setPortalError] = useState(null); const hasStripeAccount = billingStatus?.stripe_customer_id !== null; const productName = billingStatus?.product_name || ""; @@ -176,6 +178,7 @@ export function AccountMenu() { try { setIsPortalLoading(true); + setPortalError(null); const billingService = getBillingService(); const url = await billingService.getPortalUrl(); @@ -211,6 +214,9 @@ export function AccountMenu() { window.open(url, "_blank"); } catch (error) { console.error("Error fetching portal URL:", error); + setPortalError( + "Unable to open subscription management. Please try again or contact support@opensecret.cloud." + ); } finally { setIsPortalLoading(false); } @@ -448,6 +454,12 @@ export function AccountMenu() { + {portalError && ( + + + {portalError} + + )} (""); + const [portalError, setPortalError] = useState(null); const [loadingProductId, setLoadingProductId] = useState(null); const [useBitcoin, setUseBitcoin] = useState(false); const [showTeamSeatDialog, setShowTeamSeatDialog] = useState(false); @@ -476,6 +478,7 @@ function PricingPage() { const handleButtonClick = useCallback( (product: Product) => { + setPortalError(null); const targetPlanName = product.name.toLowerCase(); const isFreeplan = targetPlanName.includes("free"); const isTeamPlan = targetPlanName.includes("team"); @@ -612,6 +615,15 @@ function PricingPage() { return; } + // If the user is already on a paid plan (including team) and portal URL failed to load, + // show an error instead of silently falling through to checkout + if (isCurrentPlan) { + setPortalError( + "Unable to open subscription management. Please try again or contact support@opensecret.cloud." + ); + return; + } + // If no portal URL exists and it's not a free plan user upgrading, // create checkout session // For team plans, show seat selection dialog first @@ -785,6 +797,16 @@ function PricingPage() { )} + {/* Portal Error Message */} + {portalError && ( +
+ + + {portalError} + +
+ )} + {/* Promotion Banner */} {discount?.active && (