mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-13 17:10:06 +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:
@@ -70,6 +70,11 @@ export interface BillingState {
|
||||
* Equivalent to `subscription.value?.isActive ?? false`
|
||||
*/
|
||||
isActiveSubscription: ComputedRef<boolean>
|
||||
/**
|
||||
* Whether the current billing context has a FREE tier subscription.
|
||||
* Workspace-aware: reflects the active workspace's tier, not the user's personal tier.
|
||||
*/
|
||||
isFreeTier: ComputedRef<boolean>
|
||||
}
|
||||
|
||||
export interface BillingContext extends BillingState, BillingActions {
|
||||
|
||||
@@ -120,6 +120,8 @@ function useBillingContextInternal(): BillingContext {
|
||||
toValue(activeContext.value.isActiveSubscription)
|
||||
)
|
||||
|
||||
const isFreeTier = computed(() => subscription.value?.tier === 'FREE')
|
||||
|
||||
function getMaxSeats(tierKey: TierKey): number {
|
||||
if (type.value === 'legacy') return 1
|
||||
|
||||
@@ -238,6 +240,7 @@ function useBillingContextInternal(): BillingContext {
|
||||
isLoading,
|
||||
error,
|
||||
isActiveSubscription,
|
||||
isFreeTier,
|
||||
getMaxSeats,
|
||||
|
||||
initialize,
|
||||
|
||||
@@ -40,6 +40,7 @@ export function useLegacyBilling(): BillingState & BillingActions {
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
const isActiveSubscription = computed(() => legacyIsActiveSubscription.value)
|
||||
const isFreeTier = computed(() => subscriptionTier.value === 'FREE')
|
||||
|
||||
const subscription = computed<SubscriptionInfo | null>(() => {
|
||||
if (!legacyIsActiveSubscription.value && !subscriptionTier.value) {
|
||||
@@ -85,6 +86,10 @@ export function useLegacyBilling(): BillingState & BillingActions {
|
||||
error.value = null
|
||||
try {
|
||||
await Promise.all([fetchStatus(), fetchBalance()])
|
||||
// Re-fetch balance if free tier credits were just lazily granted
|
||||
if (isFreeTier.value && balance.value?.amountMicros === 0) {
|
||||
await fetchBalance()
|
||||
}
|
||||
isInitialized.value = true
|
||||
} catch (err) {
|
||||
error.value =
|
||||
@@ -173,6 +178,7 @@ export function useLegacyBilling(): BillingState & BillingActions {
|
||||
isLoading,
|
||||
error,
|
||||
isActiveSubscription,
|
||||
isFreeTier,
|
||||
|
||||
// Actions
|
||||
initialize,
|
||||
|
||||
Reference in New Issue
Block a user