mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-04 13:12:10 +00:00
feat: add Free subscription tier support (#8864)
## Summary Add frontend support for a Free subscription tier — login/signup page restructuring, telemetry instrumentation, and tier-aware billing gating. ## Changes - **What**: - Restructure login/signup pages: OAuth buttons promoted as primary sign-in method, email login available via progressive disclosure - Add Free tier badge on Google sign-up button with dynamic credit count from remote config - Add `FREE` subscription tier to type system (tier pricing, tier rank, registry types) - Add `isFreeTier` computed to `useSubscription()` - Disable credit top-up for Free tier users (dialogService, purchaseCredits, popover CTA) - Show subscription/upgrade dialog instead of top-up dialog when Free tier user hits out-of-credits - Add funnel telemetry: `trackLoginOpened`, enrich `trackSignupOpened` with `free_tier_badge_shown`, track email toggle clicks ## Review Focus - Tier gating logic: Free tier users should see "Upgrade" instead of "Add Credits" and never reach the top-up flow - Telemetry event design for Mixpanel funnel analysis - Progressive disclosure UX on login/signup pages ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8864-feat-add-Free-subscription-tier-support-3076d73d36508133b84ec5f0a67ccb03) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -272,7 +272,7 @@ import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
import type { components } from '@/types/comfyRegistryTypes'
|
||||
|
||||
type SubscriptionTier = components['schemas']['SubscriptionTier']
|
||||
type CheckoutTierKey = Exclude<TierKey, 'founder'>
|
||||
type CheckoutTierKey = Exclude<TierKey, 'free' | 'founder'>
|
||||
type CheckoutTier = CheckoutTierKey | `${CheckoutTierKey}-yearly`
|
||||
|
||||
const getCheckoutTier = (
|
||||
@@ -344,8 +344,12 @@ const tiers: PricingTierConfig[] = [
|
||||
isPopular: false
|
||||
}
|
||||
]
|
||||
const { isActiveSubscription, subscriptionTier, isYearlySubscription } =
|
||||
useSubscription()
|
||||
const {
|
||||
isActiveSubscription,
|
||||
isFreeTier,
|
||||
subscriptionTier,
|
||||
isYearlySubscription
|
||||
} = useSubscription()
|
||||
const telemetry = useTelemetry()
|
||||
const { userId } = storeToRefs(useFirebaseAuthStore())
|
||||
const { accessBillingPortal, reportError } = useFirebaseAuthActions()
|
||||
@@ -356,6 +360,10 @@ const loadingTier = ref<CheckoutTierKey | null>(null)
|
||||
const popover = ref()
|
||||
const currentBillingCycle = ref<BillingCycle>('yearly')
|
||||
|
||||
const hasPaidSubscription = computed(
|
||||
() => isActiveSubscription.value && !isFreeTier.value
|
||||
)
|
||||
|
||||
const currentTierKey = computed<TierKey | null>(() =>
|
||||
subscriptionTier.value ? TIER_TO_KEY[subscriptionTier.value] : null
|
||||
)
|
||||
@@ -392,7 +400,7 @@ const getButtonLabel = (tier: PricingTierConfig): string => {
|
||||
? t('subscription.tierNameYearly', { name: tier.name })
|
||||
: tier.name
|
||||
|
||||
return isActiveSubscription.value
|
||||
return hasPaidSubscription.value
|
||||
? t('subscription.changeTo', { plan: planName })
|
||||
: t('subscription.subscribeTo', { plan: planName })
|
||||
}
|
||||
@@ -427,7 +435,7 @@ const handleSubscribe = wrapWithErrorHandlingAsync(
|
||||
loadingTier.value = tierKey
|
||||
|
||||
try {
|
||||
if (isActiveSubscription.value) {
|
||||
if (hasPaidSubscription.value) {
|
||||
const checkoutAttribution = await getCheckoutAttributionForCloud()
|
||||
if (userId.value) {
|
||||
telemetry?.trackBeginCheckout({
|
||||
|
||||
Reference in New Issue
Block a user