From 0a7515b757c335900db62c9d223a1dde4ddb0f90 Mon Sep 17 00:00:00 2001 From: Simula_r <18093452+simula-r@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:24:31 -0800 Subject: [PATCH] Fix(cloud)/subscription panel (#7628) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fix subscription panel to use new shared consts for pricing info and misc plan related items. ## Changes - **What**: SubscriptionPanel.vue, /en/main.json - **Breaking**: - **Dependencies**: ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7628-Fix-cloud-subscription-panel-2ce6d73d36508119846dd537b37a0d59) by [Unito](https://www.unito.io) --- src/components/topbar/CurrentUserPopover.vue | 4 +- src/locales/en/main.json | 5 +- .../subscription/components/PricingTable.vue | 79 ++++++------ .../components/SubscriptionPanel.vue | 116 ++++++++---------- .../subscription/constants/tierPricing.ts | 52 ++++++++ 5 files changed, 145 insertions(+), 111 deletions(-) create mode 100644 src/platform/cloud/subscription/constants/tierPricing.ts diff --git a/src/components/topbar/CurrentUserPopover.vue b/src/components/topbar/CurrentUserPopover.vue index af1a3ed08..f5a6f0610 100644 --- a/src/components/topbar/CurrentUserPopover.vue +++ b/src/components/topbar/CurrentUserPopover.vue @@ -192,7 +192,9 @@ const formattedBalance = computed(() => { const canUpgrade = computed(() => { const tier = subscriptionTier.value - return tier === 'STANDARD' || tier === 'CREATOR' + return ( + tier === 'FOUNDERS_EDITION' || tier === 'STANDARD' || tier === 'CREATOR' + ) }) const handleOpenUserSettings = () => { diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 1fd76fe68..3c548f2c7 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -1988,7 +1988,7 @@ "gpuLabel": "RTX 6000 Pro (96GB VRAM)", "addCreditsLabel": "Add more credits whenever", "customLoRAsLabel": "Import your own LoRAs", - "videoEstimateLabel": "Approx. number of 5s videos generated with Wan Fun Control template", + "videoEstimateLabel": "Number of 5s videos generated with Wan Fun Control template", "videoEstimateHelp": "What is this?", "videoEstimateExplanation": "These estimates are based on the Wan Fun Control template for 5-second videos.", "videoEstimateTryTemplate": "Try the Wan Fun Control template →", @@ -1998,7 +1998,8 @@ "maxDuration": { "standard": "30 min", "creator": "30 min", - "pro": "1 hr" + "pro": "1 hr", + "founder": "30 min" } }, "userSettings": { diff --git a/src/platform/cloud/subscription/components/PricingTable.vue b/src/platform/cloud/subscription/components/PricingTable.vue index 52f8c3571..2cb309f40 100644 --- a/src/platform/cloud/subscription/components/PricingTable.vue +++ b/src/platform/cloud/subscription/components/PricingTable.vue @@ -175,7 +175,7 @@ - {{ n(tier.pricing.videoEstimate) }} + ~{{ n(tier.pricing.videoEstimate) }} @@ -253,6 +253,14 @@ import { useErrorHandling } from '@/composables/useErrorHandling' import { getComfyApiBaseUrl } from '@/config/comfyApi' import { t } from '@/i18n' import { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription' +import { + TIER_PRICING, + TIER_TO_KEY +} from '@/platform/cloud/subscription/constants/tierPricing' +import type { + TierKey, + TierPricing +} from '@/platform/cloud/subscription/constants/tierPricing' import { isCloud } from '@/platform/distribution/types' import { FirebaseAuthStoreError, @@ -261,13 +269,13 @@ import { import type { components } from '@/types/comfyRegistryTypes' type SubscriptionTier = components['schemas']['SubscriptionTier'] -type TierKey = 'standard' | 'creator' | 'pro' -type CheckoutTier = TierKey | `${TierKey}-yearly` +type CheckoutTierKey = Exclude +type CheckoutTier = CheckoutTierKey | `${CheckoutTierKey}-yearly` type BillingCycle = 'monthly' | 'yearly' const getCheckoutTier = ( - tierKey: TierKey, + tierKey: CheckoutTierKey, billingCycle: BillingCycle ): CheckoutTier => (billingCycle === 'yearly' ? `${tierKey}-yearly` : tierKey) @@ -276,22 +284,9 @@ interface BillingCycleOption { value: BillingCycle } -interface TierPricing { - monthly: number - yearly: number - credits: number - videoEstimate: number -} - -const TIER_PRICING: Record = { - standard: { monthly: 20, yearly: 16, credits: 4200, videoEstimate: 164 }, - creator: { monthly: 35, yearly: 28, credits: 7400, videoEstimate: 288 }, - pro: { monthly: 100, yearly: 80, credits: 21100, videoEstimate: 821 } -} as const - interface PricingTierConfig { id: SubscriptionTier - key: TierKey + key: CheckoutTierKey name: string pricing: TierPricing maxDuration: string @@ -304,13 +299,6 @@ const billingCycleOptions: BillingCycleOption[] = [ { label: t('subscription.monthly'), value: 'monthly' } ] -const TIER_TO_KEY: Record = { - STANDARD: 'standard', - CREATOR: 'creator', - PRO: 'pro', - FOUNDERS_EDITION: 'standard' -} - const tiers: PricingTierConfig[] = [ { id: 'STANDARD', @@ -348,7 +336,7 @@ const { accessBillingPortal, reportError } = useFirebaseAuthActions() const { wrapWithErrorHandlingAsync } = useErrorHandling() const isLoading = ref(false) -const loadingTier = ref(null) +const loadingTier = ref(null) const popover = ref() const currentBillingCycle = ref('yearly') @@ -356,7 +344,7 @@ const currentTierKey = computed(() => subscriptionTier.value ? TIER_TO_KEY[subscriptionTier.value] : null ) -const isCurrentPlan = (tierKey: TierKey): boolean => +const isCurrentPlan = (tierKey: CheckoutTierKey): boolean => currentTierKey.value === tierKey const togglePopover = (event: Event) => { @@ -391,7 +379,7 @@ const getAnnualTotal = (tier: PricingTierConfig): number => const getCreditsDisplay = (tier: PricingTierConfig): number => tier.pricing.credits * (currentBillingCycle.value === 'yearly' ? 12 : 1) -const initiateCheckout = async (tierKey: TierKey) => { +const initiateCheckout = async (tierKey: CheckoutTierKey) => { const authHeader = await getAuthHeader() if (!authHeader) { throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated')) @@ -432,24 +420,27 @@ const initiateCheckout = async (tierKey: TierKey) => { return await response.json() } -const handleSubscribe = wrapWithErrorHandlingAsync(async (tierKey: TierKey) => { - if (!isCloud || isLoading.value || isCurrentPlan(tierKey)) return +const handleSubscribe = wrapWithErrorHandlingAsync( + async (tierKey: CheckoutTierKey) => { + if (!isCloud || isLoading.value || isCurrentPlan(tierKey)) return - isLoading.value = true - loadingTier.value = tierKey + isLoading.value = true + loadingTier.value = tierKey - try { - if (isActiveSubscription.value) { - await accessBillingPortal() - } else { - const response = await initiateCheckout(tierKey) - if (response.checkout_url) { - window.open(response.checkout_url, '_blank') + try { + if (isActiveSubscription.value) { + await accessBillingPortal() + } else { + const response = await initiateCheckout(tierKey) + if (response.checkout_url) { + window.open(response.checkout_url, '_blank') + } } + } finally { + isLoading.value = false + loadingTier.value = null } - } finally { - isLoading.value = false - loadingTier.value = null - } -}, reportError) + }, + reportError +) diff --git a/src/platform/cloud/subscription/components/SubscriptionPanel.vue b/src/platform/cloud/subscription/components/SubscriptionPanel.vue index 60032de8b..75ec92c94 100644 --- a/src/platform/cloud/subscription/components/SubscriptionPanel.vue +++ b/src/platform/cloud/subscription/components/SubscriptionPanel.vue @@ -1,7 +1,7 @@