diff --git a/global.d.ts b/global.d.ts index ec455707f..7f7dd832f 100644 --- a/global.d.ts +++ b/global.d.ts @@ -30,7 +30,6 @@ interface Window { badge?: string } } - dataLayer?: Array> } interface Navigator { diff --git a/src/main.ts b/src/main.ts index 60494ca84..ca80b87f8 100644 --- a/src/main.ts +++ b/src/main.ts @@ -31,9 +31,6 @@ if (isCloud) { const { refreshRemoteConfig } = await import('@/platform/remoteConfig/refreshRemoteConfig') await refreshRemoteConfig({ useAuth: false }) - - const { initGtm } = await import('@/platform/telemetry/gtm') - initGtm() } const ComfyUIPreset = definePreset(Aura, { diff --git a/src/platform/cloud/subscription/composables/useSubscription.test.ts b/src/platform/cloud/subscription/composables/useSubscription.test.ts index 00e468de2..ffa370a90 100644 --- a/src/platform/cloud/subscription/composables/useSubscription.test.ts +++ b/src/platform/cloud/subscription/composables/useSubscription.test.ts @@ -206,49 +206,6 @@ describe('useSubscription', () => { ) }) - it('pushes purchase event after a pending subscription completes', async () => { - window.dataLayer = [] - localStorage.setItem( - 'pending_subscription_purchase', - JSON.stringify({ - tierKey: 'creator', - billingCycle: 'monthly', - timestamp: Date.now() - }) - ) - - vi.mocked(global.fetch).mockResolvedValue({ - ok: true, - json: async () => ({ - is_active: true, - subscription_id: 'sub_123', - subscription_tier: 'CREATOR', - subscription_duration: 'MONTHLY' - }) - } as Response) - - mockIsLoggedIn.value = true - const { fetchStatus } = useSubscription() - - await fetchStatus() - - expect(window.dataLayer).toHaveLength(1) - expect(window.dataLayer?.[0]).toMatchObject({ - event: 'purchase', - transaction_id: 'sub_123', - currency: 'USD', - items: [ - { - item_id: 'monthly_creator', - item_variant: 'monthly', - item_category: 'subscription', - quantity: 1 - } - ] - }) - expect(localStorage.getItem('pending_subscription_purchase')).toBeNull() - }) - it('should handle fetch errors gracefully', async () => { vi.mocked(global.fetch).mockResolvedValue({ ok: false, diff --git a/src/platform/cloud/subscription/composables/useSubscription.ts b/src/platform/cloud/subscription/composables/useSubscription.ts index 5d90f2480..7d8e8a4f8 100644 --- a/src/platform/cloud/subscription/composables/useSubscription.ts +++ b/src/platform/cloud/subscription/composables/useSubscription.ts @@ -8,20 +8,12 @@ import { getComfyApiBaseUrl, getComfyPlatformBaseUrl } from '@/config/comfyApi' import { t } from '@/i18n' import { isCloud } from '@/platform/distribution/types' import { useTelemetry } from '@/platform/telemetry' -import { pushDataLayerEvent } from '@/platform/telemetry/gtm' import { FirebaseAuthStoreError, useFirebaseAuthStore } from '@/stores/firebaseAuthStore' import { useDialogService } from '@/services/dialogService' -import { - getTierPrice, - TIER_TO_KEY -} from '@/platform/cloud/subscription/constants/tierPricing' -import { - clearPendingSubscriptionPurchase, - getPendingSubscriptionPurchase -} from '@/platform/cloud/subscription/utils/subscriptionPurchaseTracker' +import { TIER_TO_KEY } from '@/platform/cloud/subscription/constants/tierPricing' import type { operations } from '@/types/comfyRegistryTypes' import { useSubscriptionCancellationWatcher } from './useSubscriptionCancellationWatcher' @@ -101,45 +93,7 @@ function useSubscriptionInternal() { : baseName }) - function buildApiUrl(path: string): string { - return `${getComfyApiBaseUrl()}${path}` - } - - function trackSubscriptionPurchase( - status: CloudSubscriptionStatusResponse | null - ): void { - if (!status?.is_active || !status.subscription_id) return - - const pendingPurchase = getPendingSubscriptionPurchase() - if (!pendingPurchase) return - - const { tierKey, billingCycle } = pendingPurchase - const isYearly = billingCycle === 'yearly' - const baseName = t(`subscription.tiers.${tierKey}.name`) - const planName = isYearly - ? t('subscription.tierNameYearly', { name: baseName }) - : baseName - const unitPrice = getTierPrice(tierKey, isYearly) - const value = isYearly && tierKey !== 'founder' ? unitPrice * 12 : unitPrice - pushDataLayerEvent({ - event: 'purchase', - transaction_id: status.subscription_id, - value, - currency: 'USD', - items: [ - { - item_id: `${billingCycle}_${tierKey}`, - item_name: planName, - item_category: 'subscription', - item_variant: billingCycle, - price: value, - quantity: 1 - } - ] - }) - - clearPendingSubscriptionPurchase() - } + const buildApiUrl = (path: string) => `${getComfyApiBaseUrl()}${path}` const fetchStatus = wrapWithErrorHandlingAsync( fetchSubscriptionStatus, @@ -240,12 +194,6 @@ function useSubscriptionInternal() { const statusData = await response.json() subscriptionStatus.value = statusData - - try { - await trackSubscriptionPurchase(statusData) - } catch (error) { - console.error('Failed to track subscription purchase', error) - } return statusData } diff --git a/src/platform/cloud/subscription/utils/subscriptionCheckoutUtil.ts b/src/platform/cloud/subscription/utils/subscriptionCheckoutUtil.ts index 8be996ebc..746a7d616 100644 --- a/src/platform/cloud/subscription/utils/subscriptionCheckoutUtil.ts +++ b/src/platform/cloud/subscription/utils/subscriptionCheckoutUtil.ts @@ -6,7 +6,6 @@ import { 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` @@ -79,7 +78,6 @@ export async function performSubscriptionCheckout( const data = await response.json() if (data.checkout_url) { - startSubscriptionPurchaseTracking(tierKey, currentBillingCycle) if (openInNewTab) { window.open(data.checkout_url, '_blank') } else { diff --git a/src/platform/cloud/subscription/utils/subscriptionPurchaseTracker.ts b/src/platform/cloud/subscription/utils/subscriptionPurchaseTracker.ts deleted file mode 100644 index 41bbb3484..000000000 --- a/src/platform/cloud/subscription/utils/subscriptionPurchaseTracker.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { TierKey } from '@/platform/cloud/subscription/constants/tierPricing' -import type { BillingCycle } from './subscriptionTierRank' - -type PendingSubscriptionPurchase = { - tierKey: TierKey - billingCycle: BillingCycle - timestamp: number -} - -const STORAGE_KEY = 'pending_subscription_purchase' -const MAX_AGE_MS = 24 * 60 * 60 * 1000 // 24 hours -const VALID_TIERS: TierKey[] = ['standard', 'creator', 'pro', 'founder'] -const VALID_CYCLES: BillingCycle[] = ['monthly', 'yearly'] - -const safeRemove = (): void => { - try { - localStorage.removeItem(STORAGE_KEY) - } catch { - // Ignore storage errors (e.g. private browsing mode) - } -} - -export function startSubscriptionPurchaseTracking( - tierKey: TierKey, - billingCycle: BillingCycle -): void { - if (typeof window === 'undefined') return - try { - const payload: PendingSubscriptionPurchase = { - tierKey, - billingCycle, - timestamp: Date.now() - } - localStorage.setItem(STORAGE_KEY, JSON.stringify(payload)) - } catch { - // Ignore storage errors (e.g. private browsing mode) - } -} - -export function getPendingSubscriptionPurchase(): PendingSubscriptionPurchase | null { - if (typeof window === 'undefined') return null - - try { - const raw = localStorage.getItem(STORAGE_KEY) - if (!raw) return null - - const parsed = JSON.parse(raw) as PendingSubscriptionPurchase - if (!parsed || typeof parsed !== 'object') { - safeRemove() - return null - } - - const { tierKey, billingCycle, timestamp } = parsed - if ( - !VALID_TIERS.includes(tierKey) || - !VALID_CYCLES.includes(billingCycle) || - typeof timestamp !== 'number' - ) { - safeRemove() - return null - } - - if (Date.now() - timestamp > MAX_AGE_MS) { - safeRemove() - return null - } - - return parsed - } catch { - safeRemove() - return null - } -} - -export function clearPendingSubscriptionPurchase(): void { - if (typeof window === 'undefined') return - safeRemove() -} diff --git a/src/platform/telemetry/gtm.ts b/src/platform/telemetry/gtm.ts deleted file mode 100644 index d5c738ae4..000000000 --- a/src/platform/telemetry/gtm.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { isCloud } from '@/platform/distribution/types' - -const GTM_CONTAINER_ID = 'GTM-NP9JM6K7' - -let isInitialized = false -let initPromise: Promise | null = null - -export function initGtm(): void { - if (!isCloud || typeof window === 'undefined') return - if (typeof document === 'undefined') return - if (isInitialized) return - - if (!initPromise) { - initPromise = new Promise((resolve) => { - const dataLayer = window.dataLayer ?? (window.dataLayer = []) - dataLayer.push({ - 'gtm.start': Date.now(), - event: 'gtm.js' - }) - - const script = document.createElement('script') - script.async = true - script.src = `https://www.googletagmanager.com/gtm.js?id=${GTM_CONTAINER_ID}` - - const finalize = () => { - isInitialized = true - resolve() - } - - script.addEventListener('load', finalize, { once: true }) - script.addEventListener('error', finalize, { once: true }) - document.head?.appendChild(script) - }) - } - - void initPromise -} - -export function pushDataLayerEvent(event: Record): void { - if (!isCloud || typeof window === 'undefined') return - const dataLayer = window.dataLayer ?? (window.dataLayer = []) - dataLayer.push(event) -} diff --git a/src/router.ts b/src/router.ts index 365e7859e..b489d2257 100644 --- a/src/router.ts +++ b/src/router.ts @@ -9,7 +9,6 @@ import type { RouteLocationNormalized } from 'vue-router' import { useFeatureFlags } from '@/composables/useFeatureFlags' import { isCloud } from '@/platform/distribution/types' -import { pushDataLayerEvent } from '@/platform/telemetry/gtm' import { useDialogService } from '@/services/dialogService' import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' import { useUserStore } from '@/stores/userStore' @@ -37,16 +36,6 @@ function getBasePath(): string { const basePath = getBasePath() -function pushPageView(): void { - if (!isCloud || typeof window === 'undefined') return - - pushDataLayerEvent({ - event: 'page_view', - page_location: window.location.href, - page_title: document.title - }) -} - const router = createRouter({ history: isFileProtocol ? createWebHashHistory() @@ -104,10 +93,6 @@ installPreservedQueryTracker(router, [ } ]) -router.afterEach(() => { - pushPageView() -}) - if (isCloud) { const { flags } = useFeatureFlags() const PUBLIC_ROUTE_NAMES = new Set([ diff --git a/src/stores/firebaseAuthStore.ts b/src/stores/firebaseAuthStore.ts index c1c81037d..6073a4304 100644 --- a/src/stores/firebaseAuthStore.ts +++ b/src/stores/firebaseAuthStore.ts @@ -26,7 +26,6 @@ import { t } from '@/i18n' import { WORKSPACE_STORAGE_KEYS } from '@/platform/auth/workspace/workspaceConstants' import { isCloud } from '@/platform/distribution/types' import { useTelemetry } from '@/platform/telemetry' -import { pushDataLayerEvent as pushDataLayerEventBase } from '@/platform/telemetry/gtm' import { useDialogService } from '@/services/dialogService' import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore' import type { AuthHeader } from '@/types/authTypes' @@ -82,42 +81,6 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => { const buildApiUrl = (path: string) => `${getComfyApiBaseUrl()}${path}` - function pushDataLayerEvent(event: Record): void { - if (!isCloud || typeof window === 'undefined') return - - try { - pushDataLayerEventBase(event) - } catch (error) { - console.warn('Failed to push data layer event', error) - } - } - - async function hashSha256(value: string): Promise { - if (typeof crypto === 'undefined' || !crypto.subtle) return - if (typeof TextEncoder === 'undefined') return - const data = new TextEncoder().encode(value) - const hash = await crypto.subtle.digest('SHA-256', data) - return Array.from(new Uint8Array(hash)) - .map((b) => b.toString(16).padStart(2, '0')) - .join('') - } - - async function trackSignUp(method: 'email' | 'google' | 'github') { - if (!isCloud || typeof window === 'undefined') return - - try { - const userId = currentUser.value?.uid - const hashedUserId = userId ? await hashSha256(userId) : undefined - pushDataLayerEvent({ - event: 'sign_up', - method, - ...(hashedUserId ? { user_id: hashedUserId } : {}) - }) - } catch (error) { - console.warn('Failed to track sign up', error) - } - } - // Providers const googleProvider = new GoogleAuthProvider() googleProvider.addScope('email') @@ -384,7 +347,6 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => { method: 'email', is_new_user: true }) - await trackSignUp('email') } return result @@ -403,9 +365,6 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => { method: 'google', is_new_user: isNewUser }) - if (isNewUser) { - await trackSignUp('google') - } } return result @@ -424,9 +383,6 @@ export const useFirebaseAuthStore = defineStore('firebaseAuth', () => { method: 'github', is_new_user: isNewUser }) - if (isNewUser) { - await trackSignUp('github') - } } return result