From 19a3a9fc76c6df1bcf5a56137e0eba6ec4a734c1 Mon Sep 17 00:00:00 2001 From: bymyself Date: Tue, 9 Dec 2025 01:28:06 -0800 Subject: [PATCH 1/6] feat: Add Stripe pricing table integration for subscription dialog - Add StripePricingTable component with Stripe web component integration - Update subscription dialog to show Stripe pricing table when feature flag enabled - Add stripePricingTableConfig for environment-based configuration - Add useStripePricingTableLoader composable for script loading - Update dialog styling with proper width (1100px) and rounded corners - Add contact us and enterprise links to subscription dialog - Include comprehensive test coverage for new components --- .env_example | 4 + global.d.ts | 2 + src/config/stripePricingTableConfig.ts | 34 ++++ src/locales/en/main.json | 11 ++ .../components/StripePricingTable.vue | 120 ++++++++++++ .../components/SubscribeButton.vue | 35 +++- .../SubscriptionRequiredDialogContent.vue | 182 +++++++++++++++++- .../useStripePricingTableLoader.ts | 102 ++++++++++ .../composables/useSubscription.ts | 6 +- .../composables/useSubscriptionDialog.ts | 31 ++- src/platform/remoteConfig/types.ts | 2 + .../settings/composables/useSettingUI.ts | 22 ++- src/vite-env.d.ts | 9 + .../components/StripePricingTable.test.ts | 75 ++++++++ 14 files changed, 617 insertions(+), 18 deletions(-) create mode 100644 src/config/stripePricingTableConfig.ts create mode 100644 src/platform/cloud/subscription/components/StripePricingTable.vue create mode 100644 src/platform/cloud/subscription/composables/useStripePricingTableLoader.ts create mode 100644 tests-ui/tests/platform/cloud/subscription/components/StripePricingTable.test.ts diff --git a/.env_example b/.env_example index b77b87bc0e..d8624b1ec1 100644 --- a/.env_example +++ b/.env_example @@ -42,3 +42,7 @@ ALGOLIA_API_KEY=684d998c36b67a9a9fce8fc2d8860579 # SENTRY_AUTH_TOKEN=private-token # get from sentry # SENTRY_ORG=comfy-org # SENTRY_PROJECT=cloud-frontend-staging + +# Stripe pricing table configuration (used by feature-flagged subscription tiers UI) +# VITE_STRIPE_PUBLISHABLE_KEY=pk_test_123 +# VITE_STRIPE_PRICING_TABLE_ID=prctbl_123 diff --git a/global.d.ts b/global.d.ts index 7f7dd832f8..d24c7c40b5 100644 --- a/global.d.ts +++ b/global.d.ts @@ -13,6 +13,8 @@ interface Window { max_upload_size?: number comfy_api_base_url?: string comfy_platform_base_url?: string + stripe_publishable_key?: string + stripe_pricing_table_id?: string firebase_config?: { apiKey: string authDomain: string diff --git a/src/config/stripePricingTableConfig.ts b/src/config/stripePricingTableConfig.ts new file mode 100644 index 0000000000..99ba454443 --- /dev/null +++ b/src/config/stripePricingTableConfig.ts @@ -0,0 +1,34 @@ +import { remoteConfig } from '@/platform/remoteConfig/remoteConfig' + +export const STRIPE_PRICING_TABLE_SCRIPT_SRC = + 'https://js.stripe.com/v3/pricing-table.js' + +function getEnvValue( + key: 'VITE_STRIPE_PUBLISHABLE_KEY' | 'VITE_STRIPE_PRICING_TABLE_ID' +) { + return import.meta.env?.[key] +} + +export function getStripePricingTableConfig() { + const publishableKey = + remoteConfig.value.stripe_publishable_key || + window.__CONFIG__?.stripe_publishable_key || + getEnvValue('VITE_STRIPE_PUBLISHABLE_KEY') || + '' + + const pricingTableId = + remoteConfig.value.stripe_pricing_table_id || + window.__CONFIG__?.stripe_pricing_table_id || + getEnvValue('VITE_STRIPE_PRICING_TABLE_ID') || + '' + + return { + publishableKey, + pricingTableId + } +} + +export function hasStripePricingTableConfig() { + const { publishableKey, pricingTableId } = getStripePricingTableConfig() + return Boolean(publishableKey && pricingTableId) +} diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 73908a3767..f7cbee358e 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -97,6 +97,7 @@ "no": "No", "cancel": "Cancel", "close": "Close", + "or": "or", "pressKeysForNewBinding": "Press keys for new binding", "defaultBanner": "default banner", "enableOrDisablePack": "Enable or disable pack", @@ -1894,10 +1895,20 @@ "waitingForSubscription": "Complete your subscription in the new tab. We'll automatically detect when you're done!", "subscribe": "Subscribe" }, + "pricingTable": { + "description": "Access cloud-powered ComfyUI workflows with straightforward, usage-based pricing.", + "loading": "Loading pricing options...", + "loadError": "We couldn't load the pricing table. Please refresh and try again.", + "missingConfig": "Stripe pricing table configuration missing. Provide the publishable key and pricing table ID via remote config or .env." + }, "subscribeToRun": "Subscribe", "subscribeToRunFull": "Subscribe to Run", "subscribeNow": "Subscribe Now", "subscribeToComfyCloud": "Subscribe to Comfy Cloud", + "description": "Choose the best plan for you", + "haveQuestions": "Have questions or wondering about enterprise?", + "contactUs": "Contact us", + "viewEnterprise": "view enterprise", "partnerNodesCredits": "Partner Nodes pricing table" }, "userSettings": { diff --git a/src/platform/cloud/subscription/components/StripePricingTable.vue b/src/platform/cloud/subscription/components/StripePricingTable.vue new file mode 100644 index 0000000000..b2248648a0 --- /dev/null +++ b/src/platform/cloud/subscription/components/StripePricingTable.vue @@ -0,0 +1,120 @@ + + + diff --git a/src/platform/cloud/subscription/components/SubscribeButton.vue b/src/platform/cloud/subscription/components/SubscribeButton.vue index be57d3dada..f2b47d6140 100644 --- a/src/platform/cloud/subscription/components/SubscribeButton.vue +++ b/src/platform/cloud/subscription/components/SubscribeButton.vue @@ -24,8 +24,9 @@ diff --git a/src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue b/src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue index 54f32c0a8b..f85fd19bb9 100644 --- a/src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue +++ b/src/platform/cloud/subscription/components/SubscriptionRequiredDialogContent.vue @@ -1,5 +1,68 @@