mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
## Summary Add GTM injection for cloud distribution builds and push SPA page view + signup events. ## Changes - **What**: Inject GTM script into head-prepend and noscript iframe into body-prepend for cloud builds - **What**: Push `page_view` to `dataLayer` on cloud route changes (page_location + page_title) - **What**: Push `sign_up` to `dataLayer` after successful account creation (email/google/github) - **Dependencies**: None ## Review Focus - Placement order for head-prepend/body-prepend and cloud-only gating - Route-change page_view payload shape - Signup event emission only for new users ## Screenshots (if applicable) <img width="1512" height="860" alt="Screenshot 2026-01-26 at 11 38 11 AM" src="https://github.com/user-attachments/assets/03fb61db-5ca4-4432-9704-bbdcc4c6c1b7" /> <img width="1512" height="862" alt="Screenshot 2026-01-26 at 11 38 26 AM" src="https://github.com/user-attachments/assets/6e46c855-a552-4e52-9800-17898a512d4d" />
90 lines
2.7 KiB
TypeScript
90 lines
2.7 KiB
TypeScript
import { getComfyApiBaseUrl } from '@/config/comfyApi'
|
|
import { t } from '@/i18n'
|
|
import { isCloud } from '@/platform/distribution/types'
|
|
import {
|
|
FirebaseAuthStoreError,
|
|
useFirebaseAuthStore
|
|
} from '@/stores/firebaseAuthStore'
|
|
import type { TierKey } from '@/platform/cloud/subscription/constants/tierPricing'
|
|
import { startSubscriptionPurchaseTracking } from '@/platform/cloud/subscription/utils/subscriptionPurchaseTracker'
|
|
import type { BillingCycle } from './subscriptionTierRank'
|
|
|
|
type CheckoutTier = TierKey | `${TierKey}-yearly`
|
|
|
|
const getCheckoutTier = (
|
|
tierKey: TierKey,
|
|
billingCycle: BillingCycle
|
|
): CheckoutTier => (billingCycle === 'yearly' ? `${tierKey}-yearly` : tierKey)
|
|
|
|
/**
|
|
* Core subscription checkout logic shared between PricingTable and
|
|
* SubscriptionRedirectView. Handles:
|
|
* - Ensuring the user is authenticated
|
|
* - Calling the backend checkout endpoint
|
|
* - Normalizing error responses
|
|
* - Opening the checkout URL in a new tab when available
|
|
*
|
|
* Callers are responsible for:
|
|
* - Guarding on cloud-only behavior (isCloud)
|
|
* - Managing loading state
|
|
* - Wrapping with error handling (e.g. useErrorHandling)
|
|
*/
|
|
export async function performSubscriptionCheckout(
|
|
tierKey: TierKey,
|
|
currentBillingCycle: BillingCycle,
|
|
openInNewTab: boolean = true
|
|
): Promise<void> {
|
|
if (!isCloud) return
|
|
|
|
const { getFirebaseAuthHeader } = useFirebaseAuthStore()
|
|
const authHeader = await getFirebaseAuthHeader()
|
|
|
|
if (!authHeader) {
|
|
throw new FirebaseAuthStoreError(t('toastMessages.userNotAuthenticated'))
|
|
}
|
|
|
|
const checkoutTier = getCheckoutTier(tierKey, currentBillingCycle)
|
|
|
|
const response = await fetch(
|
|
`${getComfyApiBaseUrl()}/customers/cloud-subscription-checkout/${checkoutTier}`,
|
|
{
|
|
method: 'POST',
|
|
headers: { ...authHeader, 'Content-Type': 'application/json' }
|
|
}
|
|
)
|
|
|
|
if (!response.ok) {
|
|
let errorMessage = 'Failed to initiate checkout'
|
|
try {
|
|
const errorData = await response.json()
|
|
errorMessage = errorData.message || errorMessage
|
|
} catch {
|
|
// If JSON parsing fails, try to get text response or use HTTP status
|
|
try {
|
|
const errorText = await response.text()
|
|
errorMessage =
|
|
errorText || `HTTP ${response.status} ${response.statusText}`
|
|
} catch {
|
|
errorMessage = `HTTP ${response.status} ${response.statusText}`
|
|
}
|
|
}
|
|
|
|
throw new FirebaseAuthStoreError(
|
|
t('toastMessages.failedToInitiateSubscription', {
|
|
error: errorMessage
|
|
})
|
|
)
|
|
}
|
|
|
|
const data = await response.json()
|
|
|
|
if (data.checkout_url) {
|
|
startSubscriptionPurchaseTracking(tierKey, currentBillingCycle)
|
|
if (openInNewTab) {
|
|
window.open(data.checkout_url, '_blank')
|
|
} else {
|
|
globalThis.location.href = data.checkout_url
|
|
}
|
|
}
|
|
}
|