Merge pull request #14198 from supabase/hi/www-anon-session-id

fix: docs/www anon session id
This commit is contained in:
Hieu Pham authored and GitHub committed 2023-05-09 11:42:40 +07:00
commit 8769f7c191
25 files changed
+316 -71

No files matched your search

+1
View File
@@ -1,2 +1,3 @@
export const IS_PLATFORM = process.env.NEXT_PUBLIC_IS_PLATFORM === 'true'
export const LOCAL_SUPABASE = process.env.NEXT_PUBLIC_LOCAL_SUPABASE === 'true'
export const API_URL = process.env.NEXT_PUBLIC_API_URL
+1 -3
View File
@@ -1,7 +1,5 @@
interface DataProps {
referrer?: string
title: string
route?: string
[prop: string]: any
}
export const post = (url: string, data: DataProps, options = {}) => {
+1
View File
@@ -56,6 +56,7 @@
"@supabase/supabase-js": "^2.13.0",
"algoliasearch": "^4.14.2",
"babel": "^6.23.0",
"browser-session-tabs": "^3.0.0",
"clsx": "^1.2.1",
"common": "*",
"config": "*",
+19 -3
View File
@@ -1,6 +1,6 @@
import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs'
import { SessionContextProvider } from '@supabase/auth-helpers-react'
import { AuthProvider, ThemeProvider } from 'common'
import { AuthProvider, ThemeProvider, useGoogleAnalyticsProps } from 'common'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import ReactMarkdown from 'react-markdown'
@@ -10,8 +10,10 @@ import { CommandMenuProvider } from 'ui'
import components from '~/components'
import Favicons from '~/components/Favicons'
import SiteLayout from '~/layouts/SiteLayout'
import { IS_PLATFORM, LOCAL_SUPABASE } from '~/lib/constants'
import { API_URL, IS_PLATFORM, LOCAL_SUPABASE } from '~/lib/constants'
import { post } from '~/lib/fetchWrappers'
import { BrowserTabTracker } from 'browser-session-tabs'
import { v4 as uuidv4 } from 'uuid'
import '../styles/ch.scss'
import '../styles/main.scss?v=1.0.0'
import '../styles/new-docs.scss'
@@ -19,19 +21,33 @@ import '../styles/prism-okaidia.scss'
function MyApp({ Component, pageProps }: AppPropsWithLayout) {
const router = useRouter()
const googleAnalyticsProps = useGoogleAnalyticsProps()
const [supabase] = useState(() =>
IS_PLATFORM || LOCAL_SUPABASE ? createBrowserSupabaseClient() : undefined
)
function handlePageTelemetry(route: string) {
return post(`https://api.supabase.io/platform/telemetry/page`, {
return post(`${API_URL}/telemetry/page`, {
referrer: document.referrer,
title: document.title,
route,
ga: {
screen_resolution: googleAnalyticsProps?.screenResolution,
language: googleAnalyticsProps?.language,
session_id: BrowserTabTracker.sessionId,
},
})
}
useEffect(() => {
// Generate browser session id for anon tracking
BrowserTabTracker.initialize({
storageKey: 'supabase.browser.session',
sessionIdGenerator: () => uuidv4(),
})
}, [])
useEffect(() => {
function handleRouteChange(url: string) {
/*
+50 -4
View File
@@ -1,12 +1,52 @@
import { Button, Badge, IconArrowRight } from 'ui'
import SectionHeader from 'components/UI/SectionHeader'
import { Badge } from 'ui'
import Solutions from 'data/Solutions.json'
import Link from 'next/link'
import Telemetry from '~/lib/telemetry'
import gaEvents from '~/lib/gaEvents'
import SectionContainer from '../Layouts/SectionContainer'
import ProductIcon from '../ProductIcon'
import TextLink from '../TextLink'
import { useGoogleAnalyticsProps } from 'common/hooks/useGoogleAnalyticsProps'
import { useRouter } from 'next/router'
const Features = () => {
const router = useRouter()
const googleAnalyticsProps = useGoogleAnalyticsProps()
const sendTelemetryEvent = async (product: any) => {
switch (product) {
case 'Database':
return await Telemetry.sendEvent(
gaEvents['www_hp_subhero_products_database'],
googleAnalyticsProps,
router
)
case 'Authentication':
return await Telemetry.sendEvent(
gaEvents['www_hp_subhero_products_auth'],
googleAnalyticsProps,
router
)
case 'Storage':
return await Telemetry.sendEvent(
gaEvents['www_hp_subhero_products_storage'],
googleAnalyticsProps,
router
)
case 'Edge Functions':
return await Telemetry.sendEvent(
gaEvents['www_hp_subhero_products_edgeFunctions'],
googleAnalyticsProps,
router
)
case 'Realtime':
return await Telemetry.sendEvent(
gaEvents['www_hp_subhero_products_realtime'],
googleAnalyticsProps,
router
)
}
}
const IconSections = Object.values(Solutions).map((solution: any) => {
const { name, description, icon, label, url } = solution
if (solution.name === 'Realtime') return null
@@ -24,7 +64,13 @@ const Features = () => {
<Badge dot>{label}</Badge>
</div>
)}
{url && <TextLink label={label ? 'Get notified' : 'Learn more'} url={url} />}
{url && (
<TextLink
label={label ? 'Get notified' : 'Learn more'}
url={url}
onClick={() => sendTelemetryEvent(name)}
/>
)}
</div>
)
})
+16 -5
View File
@@ -1,10 +1,19 @@
import { Button, IconBookOpen, Space } from 'ui'
import Link from 'next/link'
import { Button, IconBookOpen } from 'ui'
import { useRouter } from 'next/router'
import Link from 'next/link'
import SectionContainer from './Layouts/SectionContainer'
import Telemetry, { GoogleAnalyticsEvent } from '~/lib/telemetry'
import gaEvents from '~/lib/gaEvents'
import { useGoogleAnalyticsProps } from 'common/hooks/useGoogleAnalyticsProps'
const Hero = () => {
const { basePath } = useRouter()
const router = useRouter()
const { basePath } = router
const googleAnalyticsProps = useGoogleAnalyticsProps()
const sendTelemetryEvent = async (event: GoogleAnalyticsEvent) => {
await Telemetry.sendEvent(event, googleAnalyticsProps, router)
}
return (
<div className="overflow-hidden">
@@ -40,14 +49,16 @@ const Hero = () => {
</div>
<div className="flex items-center gap-2">
<Link href="https://app.supabase.com" as="https://app.supabase.com" passHref>
<a>
<a onClick={() => sendTelemetryEvent(gaEvents['www_hp_hero_startProject'])}>
<Button size="small" className="text-white">
Start your project
</Button>
</a>
</Link>
<Link href="/docs" as="/docs" passHref>
<a>
<a
onClick={() => sendTelemetryEvent(gaEvents['www_hp_hero_documentation'])}
>
<Button size="small" type="default" icon={<IconBookOpen />}>
Documentation
</Button>
+15 -13
View File
@@ -1,20 +1,22 @@
import { IconArrowRight, IconChevronRight } from 'ui'
import { IconChevronRight } from 'ui'
import Link from 'next/link'
function TextLink({ url, label }: any) {
function TextLink({ url = '', label, ...props }: any) {
return (
<a
href={url}
className="text-scale-1100 hover:text-scale-1200 mt-3 block cursor-pointer text-sm"
>
<div className="group flex items-center gap-1">
<span className="sr-only">{`${label} about ${url}`}</span>
<span>{label}</span>
<div className="transition-all group-hover:ml-0.5">
<IconChevronRight size={14} strokeWidth={2} />
<Link href={url} passHref>
<a
className="text-scale-1100 hover:text-scale-1200 mt-3 block cursor-pointer text-sm"
{...props}
>
<div className="group flex items-center gap-1">
<span className="sr-only">{`${label} about ${url}`}</span>
<span>{label}</span>
<div className="transition-all group-hover:ml-0.5">
<IconChevronRight size={14} strokeWidth={2} />
</div>
</div>
</div>
</a>
</a>
</Link>
)
}
-8
View File
@@ -23,14 +23,6 @@
"label": "",
"url": "/storage"
},
"realtime": {
"name": "Realtime",
"icon": "M15.042 21.672L13.684 16.6m0 0l-2.51 2.225.569-9.47 5.227 7.917-3.286-.672zM12 2.25V4.5m5.834.166l-1.591 1.591M20.25 10.5H18M7.757 14.743l-1.59 1.59M6 10.5H3.75m4.007-4.243l-1.59-1.59",
"description": "Store, organize, and serve large files. Any media, including videos and images.",
"description_short": "",
"label": "",
"url": "/storage"
},
"edge-functions": {
"name": "Edge Functions",
"icon": "M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4",
+3
View File
@@ -1,5 +1,8 @@
export const APP_NAME = 'Supabase'
export const DESCRIPTION = 'The Open Source Alternative to Firebase.'
export const IS_PROD = process.env.NEXT_PUBLIC_VERCEL_ENV === 'production'
export const IS_PREVIEW = process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview'
export const API_URL = process.env.NEXT_PUBLIC_API_URL
// Launch Weeek
export const SAMPLE_TICKET_NUMBER = 1234
+1 -3
View File
@@ -1,7 +1,5 @@
interface DataProps {
referrer?: string
title: string
route?: string
[prop: string]: any
}
export const post = (url: string, data: DataProps, options = {}) => {
+45
View File
@@ -0,0 +1,45 @@
import { GoogleAnalyticsEvent } from './telemetry'
interface GoogleAnalyticsEventType {
[key: string]: GoogleAnalyticsEvent
}
const GoogleAnalyticsEvents: GoogleAnalyticsEventType = {
www_hp_hero_startProject: {
action: 'www_hp_hero_startProject',
category: 'link',
label: '',
},
www_hp_hero_documentation: {
action: 'www_hp_hero_documentation',
category: 'link',
label: '',
},
www_hp_subhero_products_database: {
action: 'www_hp_subhero_products_database',
category: 'link',
label: '',
},
www_hp_subhero_products_auth: {
action: 'www_hp_subhero_products_auth',
category: 'link',
label: '',
},
www_hp_subhero_products_storage: {
action: 'www_hp_subhero_products_storage',
category: 'link',
label: '',
},
www_hp_subhero_products_edgeFunctions: {
action: 'www_hp_subhero_products_edgeFunctions',
category: 'link',
label: '',
},
www_hp_subhero_products_realtime: {
action: 'www_hp_subhero_products_realtime',
category: 'link',
label: '',
},
}
export default GoogleAnalyticsEvents
+48
View File
@@ -0,0 +1,48 @@
import { post } from '~/lib/fetchWrapper'
import { API_URL, IS_PROD, IS_PREVIEW } from 'lib/constants'
import { BrowserTabTracker } from 'browser-session-tabs'
import { NextRouter } from 'next/router'
export interface GoogleAnalyticsEvent {
category: string
action: string
label: string
value?: string
}
export interface GoogleAnalyticsProps {
screenResolution?: string
language: string
}
// This event is the same as in studio/lib/telemetry.tx
// but uses different ENV variables for www
const sendEvent = (
event: GoogleAnalyticsEvent,
gaProps: GoogleAnalyticsProps,
router: NextRouter
) => {
if (!IS_PROD && !IS_PREVIEW) return
const { category, action, label, value } = event
return post(`${API_URL}/telemetry/event`, {
action: action,
category: category,
label: label,
value: value,
page_referrer: document?.referrer,
page_title: document?.title,
page_location: router.asPath,
ga: {
screen_resolution: gaProps?.screenResolution,
language: gaProps?.language,
session_id: BrowserTabTracker.sessionId,
},
})
}
export default {
sendEvent,
}
+1
View File
@@ -20,6 +20,7 @@
"@next/mdx": "^12.3.2",
"@supabase/auth-ui-react": "^0.1.6",
"@supabase/supabase-js": "^2.13.0",
"browser-session-tabs": "^3.0.0",
"classnames": "^2.3.1",
"cobe": "^0.6.2",
"common": "*",
+20 -4
View File
@@ -1,25 +1,41 @@
import { APP_NAME, DESCRIPTION } from 'lib/constants'
import { API_URL, APP_NAME, DESCRIPTION } from 'lib/constants'
import { DefaultSeo } from 'next-seo'
import { AppProps } from 'next/app'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
import Meta from '~/components/Favicons'
import '../styles/index.css'
import { post } from './../lib/fetchWrapper'
import { AuthProvider, ThemeProvider } from 'common'
import { post } from '~/lib/fetchWrapper'
import { AuthProvider, ThemeProvider, useGoogleAnalyticsProps } from 'common'
import { BrowserTabTracker } from 'browser-session-tabs'
import { v4 as uuidv4 } from 'uuid'
import Head from 'next/head'
export default function MyApp({ Component, pageProps }: AppProps) {
const router = useRouter()
const googleAnalyticsProps = useGoogleAnalyticsProps()
function handlePageTelemetry(route: string) {
return post(`https://api.supabase.io/platform/telemetry/page`, {
return post(`${API_URL}/telemetry/page`, {
referrer: document.referrer,
title: document.title,
route,
ga: {
screen_resolution: googleAnalyticsProps?.screenResolution,
language: googleAnalyticsProps?.language,
session_id: BrowserTabTracker.sessionId,
},
})
}
useEffect(() => {
// Generate browser session id for anon tracking
BrowserTabTracker.initialize({
storageKey: 'supabase.browser.session',
sessionIdGenerator: () => uuidv4(),
})
}, [])
useEffect(() => {
function handleRouteChange(url: string) {
handlePageTelemetry(url)
+37
View File
@@ -51,6 +51,7 @@
"@supabase/supabase-js": "^2.13.0",
"algoliasearch": "^4.14.2",
"babel": "^6.23.0",
"browser-session-tabs": "^3.0.0",
"clsx": "^1.2.1",
"common": "*",
"config": "*",
@@ -673,6 +674,7 @@
"@next/mdx": "^12.3.2",
"@supabase/auth-ui-react": "^0.1.6",
"@supabase/supabase-js": "^2.13.0",
"browser-session-tabs": "^3.0.0",
"classnames": "^2.3.1",
"cobe": "^0.6.2",
"common": "*",
@@ -12807,6 +12809,22 @@
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==",
"dev": true
},
"node_modules/browser-session-tabs": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/browser-session-tabs/-/browser-session-tabs-3.0.0.tgz",
"integrity": "sha512-HBJWkCbcDYFL+hlSGld54SF1SgaiSXnw9vaTPdDeOxT9HCTFt3hVdArIroQ3HDhh9vhqkbl6TkMjTFok0ZfwIA==",
"dependencies": {
"js-cookie": "^3.0.1"
}
},
"node_modules/browser-session-tabs/node_modules/js-cookie": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
"engines": {
"node": ">=14"
}
},
"node_modules/browserify-aes": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
@@ -39189,6 +39207,7 @@
"analytics-node": "^3.5.0",
"awesome-debounce-promise": "^2.1.0",
"blueimp-md5": "^2.19.0",
"browser-session-tabs": "^3.0.0",
"clipboard": "^2.0.8",
"clsx": "^1.2.1",
"common": "*",
@@ -48910,6 +48929,21 @@
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==",
"dev": true
},
"browser-session-tabs": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/browser-session-tabs/-/browser-session-tabs-3.0.0.tgz",
"integrity": "sha512-HBJWkCbcDYFL+hlSGld54SF1SgaiSXnw9vaTPdDeOxT9HCTFt3hVdArIroQ3HDhh9vhqkbl6TkMjTFok0ZfwIA==",
"requires": {
"js-cookie": "^3.0.1"
},
"dependencies": {
"js-cookie": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="
}
}
},
"browserify-aes": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
@@ -51538,6 +51572,7 @@
"@types/react": "17.0.39",
"algoliasearch": "^4.14.2",
"babel": "^6.23.0",
"browser-session-tabs": "^3.0.0",
"clsx": "^1.2.1",
"common": "*",
"config": "*",
@@ -66421,6 +66456,7 @@
"aws-sdk": "^2.1354.0",
"babel-loader": "^8.2.3",
"blueimp-md5": "^2.19.0",
"browser-session-tabs": "^3.0.0",
"clipboard": "^2.0.8",
"clsx": "^1.2.1",
"common": "*",
@@ -69873,6 +69909,7 @@
"@types/react-dom": "^17.0.11",
"@types/react-syntax-highlighter": "^13.5.2",
"autoprefixer": "^10.4.12",
"browser-session-tabs": "^3.0.0",
"classnames": "^2.3.1",
"cobe": "^0.6.2",
"common": "*",
+1
View File
@@ -1,2 +1,3 @@
export * from './useBreakpoint'
export * from './useParams'
export * from './useGoogleAnalyticsProps'
@@ -0,0 +1,12 @@
import { useRouter } from 'next/router'
const isBrowser = typeof window !== 'undefined'
export function useGoogleAnalyticsProps() {
const { locale } = useRouter()
return {
screenResolution: isBrowser ? `${window.innerWidth}x${window.innerHeight}` : undefined,
language: locale ?? 'en-US',
}
}
@@ -8,7 +8,7 @@ import { useProfileQuery } from 'data/profile/profile-query'
import { SQL_TEMPLATES } from 'components/interfaces/SQLEditor/SQLEditor.constants'
import SQLCard from './SQLCard'
import { createSqlSnippetSkeleton } from '../SQLEditor.utils'
import { useParams } from 'common'
import { useGoogleAnalyticsProps, useParams } from 'common'
import { useRouter } from 'next/router'
import { SqlSnippet } from 'data/content/sql-snippets-query'
import { useSqlEditorStateSnapshot } from 'state/sql-editor'
@@ -21,6 +21,7 @@ const SQLTemplates = observer(() => {
const { data: profile } = useProfileQuery()
const [sql, quickStart] = partition(SQL_TEMPLATES, { type: 'template' })
const googleAnalyticsProps = useGoogleAnalyticsProps()
const snap = useSqlEditorStateSnapshot()
const canCreateSQLSnippet = checkPermissions(PermissionAction.CREATE, 'user_content', {
resource: { type: 'sql', owner_id: profile?.id },
@@ -77,7 +78,8 @@ const SQLTemplates = observer(() => {
action: 'script_clicked',
label: x.title,
},
ui.googleAnalyticsProps
googleAnalyticsProps,
router
)
}}
/>
@@ -111,7 +113,8 @@ const SQLTemplates = observer(() => {
action: 'quickstart_clicked',
label: x.title,
},
ui.googleAnalyticsProps
googleAnalyticsProps,
router
)
}}
/>
@@ -9,6 +9,8 @@ import { CSVLink } from 'react-csv'
import { useSqlEditorStateSnapshot } from 'state/sql-editor'
// @ts-ignore
import MarkdownTable from 'markdown-table'
import { useGoogleAnalyticsProps } from 'common'
import { useRouter } from 'next/router'
export type ResultsDropdownProps = {
id: string
@@ -17,9 +19,11 @@ export type ResultsDropdownProps = {
const ResultsDropdown = ({ id }: ResultsDropdownProps) => {
const { project } = useProjectContext()
const snap = useSqlEditorStateSnapshot()
const googleAnalyticsProps = useGoogleAnalyticsProps()
const result = snap.results?.[id]?.[0] ?? undefined
const { ui } = useStore()
const csvRef = useRef<CSVLink & HTMLAnchorElement & { link: HTMLAnchorElement }>(null)
const router = useRouter()
const csvData = useMemo(
() => (result?.rows ? compact(Array.from(result.rows || [])) : ''),
@@ -30,7 +34,8 @@ const ResultsDropdown = ({ id }: ResultsDropdownProps) => {
csvRef.current?.link.click()
Telemetry.sendEvent(
{ category: 'sql_editor', action: 'sql_download_csv', label: '' },
ui.googleAnalyticsProps
googleAnalyticsProps,
router
)
}
@@ -53,7 +58,8 @@ const ResultsDropdown = ({ id }: ResultsDropdownProps) => {
ui.setNotification({ category: 'success', message: 'Copied results to clipboard' })
Telemetry.sendEvent(
{ category: 'sql_editor', action: 'sql_copy_as_markdown', label: '' },
ui.googleAnalyticsProps
googleAnalyticsProps,
router
)
})
}
+6 -4
View File
@@ -1,4 +1,5 @@
import { useStore } from 'hooks'
import { BrowserTabTracker } from 'browser-session-tabs'
import { useGoogleAnalyticsProps } from 'common'
import { post } from 'lib/common/fetch'
import { API_URL, IS_PLATFORM } from 'lib/constants'
import { observer } from 'mobx-react-lite'
@@ -25,7 +26,7 @@ function sanitizePageViewRoute(_route?: string) {
const PageTelemetry: FC = ({ children }) => {
const router = useRouter()
const { ui } = useStore()
const googleAnalyticsProps = useGoogleAnalyticsProps()
useEffect(() => {
function handleRouteChange(url: string) {
@@ -71,8 +72,9 @@ const PageTelemetry: FC = ({ children }) => {
title: document.title,
route,
ga: {
screen_resolution: ui.googleAnalyticsProps?.screenResolution,
language: ui.googleAnalyticsProps?.language,
screen_resolution: googleAnalyticsProps?.screenResolution,
language: googleAnalyticsProps?.language,
session_id: BrowserTabTracker.sessionId,
},
})
}
+4 -2
View File
@@ -1,18 +1,20 @@
import {
AuthContext as AuthContextInternal,
AuthProvider as AuthProviderInternal,
AuthProviderProps,
gotrueClient,
useGoogleAnalyticsProps,
} from 'common'
import { useProfileQuery } from 'data/profile/profile-query'
import { useStore } from 'hooks'
import { PropsWithChildren, useEffect } from 'react'
import { GOTRUE_ERRORS, IS_PLATFORM } from './constants'
import Telemetry from 'lib/telemetry'
export const AuthContext = AuthContextInternal
export const AuthProvider = ({ children }: PropsWithChildren<{}>) => {
const { ui, app } = useStore()
const googleAnalyticsProps = useGoogleAnalyticsProps()
// Check for unverified GitHub users after a GitHub sign in
useEffect(() => {
@@ -34,7 +36,7 @@ export const AuthProvider = ({ children }: PropsWithChildren<{}>) => {
// Track telemetry for the current user
useProfileQuery({
onSuccess(profile) {
ui.setProfile(profile)
Telemetry.sendIdentify(profile, googleAnalyticsProps)
// [Joshen] Temp fix: For new users, the GET profile call also creates a default org
// But because the dashboard's logged in state is using gotrue as the source of truth
+9 -1
View File
@@ -1,6 +1,8 @@
import { post } from 'lib/common/fetch'
import { API_URL, IS_PLATFORM } from 'lib/constants'
import { User } from 'types'
import { BrowserTabTracker } from 'browser-session-tabs'
import { NextRouter } from 'next/router'
export interface GoogleAnalyticsProps {
screenResolution?: string
@@ -14,7 +16,8 @@ const sendEvent = (
label: string
value?: string
},
gaProps?: GoogleAnalyticsProps
gaProps: GoogleAnalyticsProps,
router: NextRouter
) => {
if (!IS_PLATFORM) return
@@ -25,9 +28,13 @@ const sendEvent = (
category: category,
label: label,
value: value,
page_referrer: document?.referrer,
page_title: document?.title,
page_location: router.asPath,
ga: {
screen_resolution: gaProps?.screenResolution,
language: gaProps?.language,
session_id: BrowserTabTracker.sessionId,
},
})
}
@@ -44,6 +51,7 @@ const sendIdentify = (user: User, gaProps?: GoogleAnalyticsProps) => {
ga: {
screen_resolution: gaProps?.screenResolution,
language: gaProps?.language,
session_id: BrowserTabTracker.sessionId,
},
})
}
+1
View File
@@ -41,6 +41,7 @@
"analytics-node": "^3.5.0",
"awesome-debounce-promise": "^2.1.0",
"blueimp-md5": "^2.19.0",
"browser-session-tabs": "^3.0.0",
"clipboard": "^2.0.8",
"clsx": "^1.2.1",
"common": "*",
+10
View File
@@ -50,6 +50,8 @@ import Favicons from 'components/head/Favicons'
import { IS_PLATFORM } from 'lib/constants'
import { SessionContextProvider } from '@supabase/auth-helpers-react'
import { createClient } from '@supabase/supabase-js'
import { BrowserTabTracker } from 'browser-session-tabs'
import { v4 as uuidv4 } from 'uuid'
dayjs.extend(customParseFormat)
dayjs.extend(utc)
@@ -74,6 +76,14 @@ function CustomApp({ Component, pageProps }: AppPropsWithLayout) {
const getSavingState = () => rootStore.content.savingState
useEffect(() => {
// Generate browser session id for anon tracking
BrowserTabTracker.initialize({
storageKey: 'supabase.browser.session',
sessionIdGenerator: () => uuidv4(),
})
}, [])
// prompt the user if they try and leave with unsaved content store changes
useEffect(() => {
const warningText = 'You have unsaved changes - are you sure you wish to leave this page?'
+1 -16
View File
@@ -1,8 +1,7 @@
import { uuidv4 } from 'lib/helpers'
import { action, makeAutoObservable } from 'mobx'
import { Project, Notification, User, Organization, ProjectBase, Permission } from 'types'
import { Project, Notification, Organization, ProjectBase, Permission } from 'types'
import { IRootStore } from './RootStore'
import Telemetry, { GoogleAnalyticsProps } from 'lib/telemetry'
export interface IUiStore {
language: 'en-US'
@@ -12,12 +11,10 @@ export interface IUiStore {
selectedOrganization?: Organization
notification?: Notification
permissions?: Permission[]
googleAnalyticsProps?: GoogleAnalyticsProps
load: () => void
setProjectRef: (ref?: string) => void
setOrganizationSlug: (slug?: string) => void
setNotification: (notification: Notification) => string
setProfile: (value: User) => void
setPermissions: (permissions?: Permission[]) => void
}
export default class UiStore implements IUiStore {
@@ -83,14 +80,6 @@ export default class UiStore implements IUiStore {
return undefined
}
get googleAnalyticsProps() {
return {
screenResolution:
typeof window !== 'undefined' ? `${window.innerWidth}x${window.innerHeight}` : undefined,
language: this.language,
}
}
load() {
if (typeof window === 'undefined') return
}
@@ -109,10 +98,6 @@ export default class UiStore implements IUiStore {
return id
}
setProfile(value: User) {
Telemetry.sendIdentify(value, this.googleAnalyticsProps)
}
setPermissions(permissions?: any) {
this.permissions = permissions
}