mirror of
https://github.com/supabase/supabase.git
synced 2026-10-14 21:59:16 +03:00
* Add third-parties dependency for GTM. Reexport the GTM from the common package. * Add the TelemetryTagManager to four of the production apps. * Add the GOOGLE_TAG_MANAGER_ID env var as a turbo dependency to the 4 apps. * Skip rendering the tag manager if the env var is not set or not running on the platform. * Fix the prop type to be extracted from the component. * Add default values for consent to GTM. * Another try to mimic gtag function. * Fix a link in www. * Try another approach. * try. * Remove the data-redaction flag. * Remove extra code. * Send a sign-up event if GTM is enabled. * Send only the email to GTM. * Minor fixes. * Remove third-parties from pnpm lockfile. * Lets try to make studio work again. * Add CSP rules for img loading for GTM. * Add event for testing. * Add www.googletagmanager.com to the CSP rules. * Add Stape to CSP rules. * Fix stape CSP. * Clean up the code. * Remove extra console.log. * Fix the stape urls for CORS. * Fix the wrong category for Stape URL. * Add google ads urls. * Bump the timeout. * Add google.com to the img-src for google ads. * update csp * remove comment * update to use google analytics without signals * add stape to default-src in csp * move csp to middleware * add google ads support and fix middleware base path * remove google tag manager / google ads references from csp. load via stape proxy instead * add double click url to image src * add Google Tag Manager URL to CSP configuration * add ga4 urls to csp * remove google urls from CSP --------- Co-authored-by: Alaister Young <a@alaisteryoung.com>
96 lines
3.8 KiB
TypeScript
96 lines
3.8 KiB
TypeScript
/* eslint-disable react-hooks/rules-of-hooks */
|
|
import * as Sentry from '@sentry/nextjs'
|
|
import { useRouter } from 'next/router'
|
|
import { useEffect } from 'react'
|
|
|
|
import { LOCAL_STORAGE_KEYS, useParams, useTelemetryCookie, useUser } from 'common'
|
|
import { useSendGroupsIdentifyMutation } from 'data/telemetry/send-groups-identify-mutation'
|
|
import { useSendGroupsResetMutation } from 'data/telemetry/send-groups-reset-mutation'
|
|
import { usePrevious } from 'hooks/deprecated'
|
|
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
|
import { IS_PLATFORM } from 'lib/constants'
|
|
|
|
const getAnonId = async (id: string) => {
|
|
const encoder = new TextEncoder()
|
|
const data = encoder.encode(id)
|
|
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
|
|
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
|
const base64String = btoa(hashArray.map((byte) => String.fromCharCode(byte)).join(''))
|
|
|
|
return base64String
|
|
}
|
|
|
|
const GroupsTelemetry = ({ hasAcceptedConsent }: { hasAcceptedConsent: boolean }) => {
|
|
// Although this is "technically" breaking the rules of hooks
|
|
// IS_PLATFORM never changes within a session, so this won't cause any issues
|
|
if (!IS_PLATFORM) return null
|
|
|
|
const user = useUser()
|
|
const router = useRouter()
|
|
const { ref, slug } = useParams()
|
|
const organization = useSelectedOrganization()
|
|
|
|
const previousPathname = usePrevious(router.pathname)
|
|
|
|
const { mutate: sendGroupsIdentify } = useSendGroupsIdentifyMutation()
|
|
const { mutate: sendGroupsReset } = useSendGroupsResetMutation()
|
|
|
|
const title = typeof document !== 'undefined' ? document?.title : ''
|
|
const referrer = typeof document !== 'undefined' ? document?.referrer : ''
|
|
useTelemetryCookie({ hasAcceptedConsent, title, referrer })
|
|
|
|
useEffect(() => {
|
|
// don't set the sentry user id if the user hasn't logged in (so that Sentry errors show null user id instead of anonymous id)
|
|
if (!user?.id) {
|
|
return
|
|
}
|
|
|
|
const setSentryId = async () => {
|
|
let sentryUserId = localStorage.getItem(LOCAL_STORAGE_KEYS.SENTRY_USER_ID)
|
|
if (!sentryUserId) {
|
|
sentryUserId = await getAnonId(user?.id)
|
|
localStorage.setItem(LOCAL_STORAGE_KEYS.SENTRY_USER_ID, sentryUserId)
|
|
}
|
|
Sentry.setUser({ id: sentryUserId })
|
|
}
|
|
|
|
// if an error happens, continue without setting a sentry id
|
|
setSentryId().catch((e) => console.error(e))
|
|
}, [user?.id])
|
|
|
|
useEffect(() => {
|
|
const isLandingOnProjectRoute =
|
|
router.pathname.includes('[ref]') && previousPathname === router.pathname
|
|
const isEnteringProjectRoute =
|
|
!(previousPathname ?? '').includes('[ref]') && router.pathname.includes('[ref]')
|
|
const isLeavingProjectRoute =
|
|
(previousPathname ?? '').includes('[ref]') && !router.pathname.includes('[ref]')
|
|
|
|
const isLandingOnOrgRoute =
|
|
router.pathname.includes('[slug]') && previousPathname === router.pathname
|
|
const isEnteringOrgRoute =
|
|
!(previousPathname ?? '').includes('[slug]') && router.pathname.includes('[slug]')
|
|
const isLeavingOrgRoute =
|
|
(previousPathname ?? '').includes('[slug]') && !router.pathname.includes('[slug]')
|
|
|
|
if (hasAcceptedConsent) {
|
|
if (ref && (isLandingOnProjectRoute || isEnteringProjectRoute)) {
|
|
sendGroupsIdentify({ organization_slug: organization?.slug, project_ref: ref as string })
|
|
} else if (slug && (isLandingOnOrgRoute || isEnteringOrgRoute)) {
|
|
sendGroupsIdentify({ organization_slug: slug, project_ref: undefined })
|
|
} else if (isLeavingProjectRoute || isLeavingOrgRoute) {
|
|
sendGroupsReset({
|
|
reset_organization: isLeavingOrgRoute || isLeavingProjectRoute,
|
|
reset_project: isLeavingProjectRoute,
|
|
})
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [hasAcceptedConsent, slug, ref, router.pathname])
|
|
|
|
return null
|
|
}
|
|
|
|
export default GroupsTelemetry
|