diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx
index f5c6229748..1c47ad2a81 100644
--- a/frontend/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx
+++ b/frontend/src/proprietary/components/shared/config/configSections/AdminPlanSection.tsx
@@ -1,5 +1,5 @@
import React, { useState, useCallback, useEffect } from 'react';
-import { Divider, Loader, Alert, Select, Group, Text, Collapse, Button, TextInput, Stack, Paper } from '@mantine/core';
+import { Divider, Loader, Alert, Group, Text, Collapse, Button, TextInput, Stack, Paper } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import { usePlans } from '@app/hooks/usePlans';
import licenseService, { PlanTierGroup, mapLicenseToTier } from '@app/services/licenseService';
@@ -9,8 +9,6 @@ import AvailablePlansSection from '@app/components/shared/config/configSections/
import StaticPlanSection from '@app/components/shared/config/configSections/plan/StaticPlanSection';
import { alert } from '@app/components/toast';
import LocalIcon from '@app/components/shared/LocalIcon';
-import { Z_INDEX_OVER_CONFIG_MODAL } from '@app/styles/zIndex';
-import { ManageBillingButton } from '@app/components/shared/ManageBillingButton';
import { isSupabaseConfigured } from '@app/services/supabaseClient';
const AdminPlanSection: React.FC = () => {
@@ -80,6 +78,30 @@ const AdminPlanSection: React.FC = () => {
{ value: 'idr', label: 'Indonesian rupiah (IDR, Rp)' },
];
+ const handleManageClick = useCallback(async () => {
+ try {
+ if (!licenseInfo?.licenseKey) {
+ throw new Error('No license key found. Please activate a license first.');
+ }
+
+ // Create billing portal session with license key
+ const response = await licenseService.createBillingPortalSession(
+ window.location.href,
+ licenseInfo.licenseKey
+ );
+
+ // Open billing portal in new tab
+ window.open(response.url, '_blank');
+ } catch (error: any) {
+ console.error('Failed to open billing portal:', error);
+ alert({
+ alertType: 'error',
+ title: t('billing.portal.error', 'Failed to open billing portal'),
+ body: error.message || 'Please try again or contact support.',
+ });
+ }
+ }, [licenseInfo, t]);
+
const handleUpgradeClick = useCallback(
(planGroup: PlanTierGroup) => {
// Only allow upgrades for server and enterprise tiers
@@ -143,40 +165,14 @@ const AdminPlanSection: React.FC = () => {
return (
- {/* Currency Selection & Manage Subscription */}
-
-
-
-
- {t('plan.currency', 'Currency')}
-
-
-
- {/* Manage Subscription Button - Only show if user has active license and Supabase is configured */}
- {licenseInfo?.licenseKey && isSupabaseConfigured && (
-
-
- {t('plan.manageSubscription.description', 'Manage your subscription, billing, and payment methods')}
-
-
-
- )}
-
-
-
diff --git a/frontend/src/proprietary/components/shared/config/configSections/plan/AvailablePlansSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/plan/AvailablePlansSection.tsx
index 79911b1250..408e9f1eae 100644
--- a/frontend/src/proprietary/components/shared/config/configSections/plan/AvailablePlansSection.tsx
+++ b/frontend/src/proprietary/components/shared/config/configSections/plan/AvailablePlansSection.tsx
@@ -1,21 +1,30 @@
import React, { useState, useMemo } from 'react';
-import { Button, Collapse } from '@mantine/core';
+import { Button, Collapse, Select, Group } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import licenseService, { PlanTier, PlanTierGroup, LicenseInfo, mapLicenseToTier } from '@app/services/licenseService';
import PlanCard from '@app/components/shared/config/configSections/plan/PlanCard';
import FeatureComparisonTable from '@app/components/shared/config/configSections/plan/FeatureComparisonTable';
+import { Z_INDEX_OVER_CONFIG_MODAL } from '@app/styles/zIndex';
interface AvailablePlansSectionProps {
plans: PlanTier[];
currentPlanId?: string;
currentLicenseInfo?: LicenseInfo | null;
onUpgradeClick: (planGroup: PlanTierGroup) => void;
+ onManageClick?: () => void;
+ currency?: string;
+ onCurrencyChange?: (currency: string) => void;
+ currencyOptions?: { value: string; label: string }[];
}
const AvailablePlansSection: React.FC
= ({
plans,
currentLicenseInfo,
onUpgradeClick,
+ onManageClick,
+ currency,
+ onCurrencyChange,
+ currencyOptions,
}) => {
const { t } = useTranslation();
const [showComparison, setShowComparison] = useState(false);
@@ -58,18 +67,33 @@ const AvailablePlansSection: React.FC = ({
return (
-
- {t('plan.availablePlans.title', 'Available Plans')}
-
-
- {t('plan.availablePlans.subtitle', 'Choose the plan that fits your needs')}
-
+
+
+
+ {t('plan.availablePlans.title', 'Available Plans')}
+
+
+ {t('plan.availablePlans.subtitle', 'Choose the plan that fits your needs')}
+
+
+ {currency && onCurrencyChange && currencyOptions && (
+
= ({
currentLicenseInfo={currentLicenseInfo}
currentTier={currentTier}
onUpgradeClick={onUpgradeClick}
+ onManageClick={onManageClick}
/>
))}
diff --git a/frontend/src/proprietary/components/shared/config/configSections/plan/PlanCard.tsx b/frontend/src/proprietary/components/shared/config/configSections/plan/PlanCard.tsx
index 2594d91d48..564f6c11b6 100644
--- a/frontend/src/proprietary/components/shared/config/configSections/plan/PlanCard.tsx
+++ b/frontend/src/proprietary/components/shared/config/configSections/plan/PlanCard.tsx
@@ -14,9 +14,10 @@ interface PlanCardProps {
currentLicenseInfo?: LicenseInfo | null;
currentTier?: 'free' | 'server' | 'enterprise' | null;
onUpgradeClick: (planGroup: PlanTierGroup) => void;
+ onManageClick?: () => void;
}
-const PlanCard: React.FC
= ({ planGroup, isCurrentTier, isDowngrade, currentLicenseInfo, currentTier, onUpgradeClick }) => {
+const PlanCard: React.FC = ({ planGroup, isCurrentTier, isDowngrade, currentLicenseInfo, currentTier, onUpgradeClick, onManageClick }) => {
const { t } = useTranslation();
// Render Free plan
@@ -160,15 +161,15 @@ const PlanCard: React.FC = ({ planGroup, isCurrentTier, isDowngra
withArrow
>