WIP
This commit is contained in:
@@ -28,6 +28,10 @@ EXPO_PUBLIC_CHAT_PROXY_DID=
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# Growthbook config
|
||||||
|
EXPO_PUBLIC_GROWTHBOOK_API_HOST=
|
||||||
|
EXPO_PUBLIC_GROWTHBOOK_CLIENT_KEY=
|
||||||
|
|
||||||
# Sentry DSN for telemetry
|
# Sentry DSN for telemetry
|
||||||
EXPO_PUBLIC_SENTRY_DSN=
|
EXPO_PUBLIC_SENTRY_DSN=
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,7 @@
|
|||||||
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
"@fortawesome/free-regular-svg-icons": "^6.1.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.1.1",
|
"@fortawesome/free-solid-svg-icons": "^6.1.1",
|
||||||
"@fortawesome/react-native-fontawesome": "^0.3.2",
|
"@fortawesome/react-native-fontawesome": "^0.3.2",
|
||||||
|
"@growthbook/growthbook-react": "^1.6.2",
|
||||||
"@haileyok/bluesky-video": "0.3.2",
|
"@haileyok/bluesky-video": "0.3.2",
|
||||||
"@ipld/dag-cbor": "^9.2.0",
|
"@ipld/dag-cbor": "^9.2.0",
|
||||||
"@lingui/react": "^4.14.1",
|
"@lingui/react": "^4.14.1",
|
||||||
|
|||||||
+4
-2
@@ -21,7 +21,7 @@ import {Provider as StatsigProvider, tryFetchGates} from '#/lib/statsig/statsig'
|
|||||||
import {s} from '#/lib/styles'
|
import {s} from '#/lib/styles'
|
||||||
import {ThemeProvider} from '#/lib/ThemeContext'
|
import {ThemeProvider} from '#/lib/ThemeContext'
|
||||||
import I18nProvider from '#/locale/i18nProvider'
|
import I18nProvider from '#/locale/i18nProvider'
|
||||||
import {logger} from '#/logger'
|
import {logger, Provider as LoggingProvider} from '#/logger'
|
||||||
import {Provider as A11yProvider} from '#/state/a11y'
|
import {Provider as A11yProvider} from '#/state/a11y'
|
||||||
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
|
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
|
||||||
import {Provider as DialogStateProvider} from '#/state/dialogs'
|
import {Provider as DialogStateProvider} from '#/state/dialogs'
|
||||||
@@ -238,7 +238,9 @@ function App() {
|
|||||||
<StarterPackProvider>
|
<StarterPackProvider>
|
||||||
<SafeAreaProvider
|
<SafeAreaProvider
|
||||||
initialMetrics={initialWindowMetrics}>
|
initialMetrics={initialWindowMetrics}>
|
||||||
<InnerApp />
|
<LoggingProvider>
|
||||||
|
<InnerApp />
|
||||||
|
</LoggingProvider>
|
||||||
</SafeAreaProvider>
|
</SafeAreaProvider>
|
||||||
</StarterPackProvider>
|
</StarterPackProvider>
|
||||||
</BottomSheetProvider>
|
</BottomSheetProvider>
|
||||||
|
|||||||
+6
-2
@@ -12,7 +12,8 @@ import {QueryProvider} from '#/lib/react-query'
|
|||||||
import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
|
import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
|
||||||
import {ThemeProvider} from '#/lib/ThemeContext'
|
import {ThemeProvider} from '#/lib/ThemeContext'
|
||||||
import I18nProvider from '#/locale/i18nProvider'
|
import I18nProvider from '#/locale/i18nProvider'
|
||||||
import {logger} from '#/logger'
|
import {logger, Provider as LoggingProvider} from '#/logger'
|
||||||
|
import {initializer as growthbookInitializer} from '#/logger/growthbook/context'
|
||||||
import {Provider as A11yProvider} from '#/state/a11y'
|
import {Provider as A11yProvider} from '#/state/a11y'
|
||||||
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
|
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
|
||||||
import {Provider as DialogStateProvider} from '#/state/dialogs'
|
import {Provider as DialogStateProvider} from '#/state/dialogs'
|
||||||
@@ -85,6 +86,7 @@ function InnerApp() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function onLaunch(account?: SessionAccount) {
|
async function onLaunch(account?: SessionAccount) {
|
||||||
try {
|
try {
|
||||||
|
await growthbookInitializer
|
||||||
if (account) {
|
if (account) {
|
||||||
await resumeSession(account)
|
await resumeSession(account)
|
||||||
}
|
}
|
||||||
@@ -205,7 +207,9 @@ function App() {
|
|||||||
<LightboxStateProvider>
|
<LightboxStateProvider>
|
||||||
<PortalProvider>
|
<PortalProvider>
|
||||||
<StarterPackProvider>
|
<StarterPackProvider>
|
||||||
<InnerApp />
|
<LoggingProvider>
|
||||||
|
<InnerApp />
|
||||||
|
</LoggingProvider>
|
||||||
</StarterPackProvider>
|
</StarterPackProvider>
|
||||||
</PortalProvider>
|
</PortalProvider>
|
||||||
</LightboxStateProvider>
|
</LightboxStateProvider>
|
||||||
|
|||||||
Vendored
+11
@@ -84,6 +84,17 @@ export const BLUESKY_PROXY_DID: Did =
|
|||||||
export const CHAT_PROXY_DID: Did =
|
export const CHAT_PROXY_DID: Did =
|
||||||
process.env.EXPO_PUBLIC_CHAT_PROXY_DID || 'did:web:api.bsky.chat'
|
process.env.EXPO_PUBLIC_CHAT_PROXY_DID || 'did:web:api.bsky.chat'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Growthbook API host
|
||||||
|
*/
|
||||||
|
export const GROWTHBOOK_API_HOST: string | undefined = process.env.EXPO_PUBLIC_GROWTHBOOK_API_HOST
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Growthbook client key
|
||||||
|
*/
|
||||||
|
export const GROWTHBOOK_CLIENT_KEY: string | undefined = process.env.EXPO_PUBLIC_GROWTHBOOK_CLIENT_KEY
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sentry DSN for telemetry
|
* Sentry DSN for telemetry
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import {useMemo, useEffect} from 'react'
|
||||||
|
import {Platform} from 'react-native'
|
||||||
|
import {
|
||||||
|
GrowthBook,
|
||||||
|
GrowthBookProvider,
|
||||||
|
useFeatureIsOn,
|
||||||
|
} from '@growthbook/growthbook-react'
|
||||||
|
|
||||||
|
import * as env from '#/env'
|
||||||
|
import {useSession, SessionAccount} from '#/state/session'
|
||||||
|
import {useGeolocation} from '#/geolocation'
|
||||||
|
import * as persisted from '#/state/persisted'
|
||||||
|
import * as referrer from '#/logger/growthbook/util/referrer'
|
||||||
|
|
||||||
|
type DefaultAttributes = {
|
||||||
|
country: string
|
||||||
|
}
|
||||||
|
type UserAttributes = {
|
||||||
|
id: string
|
||||||
|
pds: string | undefined
|
||||||
|
platform: string
|
||||||
|
appVersion: string
|
||||||
|
bundleIdentifier: string
|
||||||
|
bundleDate: number
|
||||||
|
refSrc: string
|
||||||
|
refUrl: string
|
||||||
|
appLanguage: string
|
||||||
|
contentLanguages: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const gb = new GrowthBook({
|
||||||
|
apiHost: env.GROWTHBOOK_API_HOST,
|
||||||
|
clientKey: env.GROWTHBOOK_CLIENT_KEY,
|
||||||
|
trackingCallback: (experiment, result) => {
|
||||||
|
// TODO
|
||||||
|
console.log('Experiment Viewed', {
|
||||||
|
experimentId: experiment.key,
|
||||||
|
variationId: result.key,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const initializer = gb.init({
|
||||||
|
timeout: 1e3,
|
||||||
|
})
|
||||||
|
|
||||||
|
export function useGate(gate: string): boolean {
|
||||||
|
return useFeatureIsOn(gate)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Provider({children}: {children: React.ReactNode}) {
|
||||||
|
const geo = useGeolocation()
|
||||||
|
const {currentAccount} = useSession()
|
||||||
|
const defaultAttributes = useMemo<DefaultAttributes>(
|
||||||
|
() => ({
|
||||||
|
country: geo.countryCode || 'unknown',
|
||||||
|
}),
|
||||||
|
[geo],
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorate existing attributes with any new default attributes
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
const attr = {
|
||||||
|
...gb.getAttributes(),
|
||||||
|
...defaultAttributes,
|
||||||
|
}
|
||||||
|
gb.setAttributes(attr)
|
||||||
|
console.debug(`update attributes`, {attributes: attr})
|
||||||
|
}, [defaultAttributes])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update user attributes on session change, and clear them on logout
|
||||||
|
*/
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentAccount) {
|
||||||
|
const attr = getUserAttributes(currentAccount)
|
||||||
|
gb.setAttributes({
|
||||||
|
...defaultAttributes,
|
||||||
|
...getUserAttributes(currentAccount),
|
||||||
|
})
|
||||||
|
console.debug(`has session, set attributes`, {attributes: attr})
|
||||||
|
} else {
|
||||||
|
gb.setAttributes(defaultAttributes)
|
||||||
|
console.debug(`no session, reset attributes`, {
|
||||||
|
attributes: defaultAttributes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [defaultAttributes, currentAccount])
|
||||||
|
|
||||||
|
return <GrowthBookProvider growthbook={gb}>{children}</GrowthBookProvider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserAttributes(account: SessionAccount): UserAttributes
|
||||||
|
export function getUserAttributes(account: undefined): null
|
||||||
|
export function getUserAttributes(
|
||||||
|
account?: SessionAccount,
|
||||||
|
): UserAttributes | null {
|
||||||
|
if (!account) return null
|
||||||
|
const languagePrefs = persisted.get('languagePrefs')
|
||||||
|
return {
|
||||||
|
id: account.did,
|
||||||
|
pds: account.pdsUrl,
|
||||||
|
platform: Platform.OS,
|
||||||
|
appVersion: env.RELEASE_VERSION,
|
||||||
|
bundleIdentifier: env.BUNDLE_IDENTIFIER,
|
||||||
|
bundleDate: env.BUNDLE_DATE,
|
||||||
|
appLanguage: languagePrefs.appLanguage,
|
||||||
|
contentLanguages: languagePrefs.contentLanguages,
|
||||||
|
refSrc: referrer.src,
|
||||||
|
refUrl: referrer.url,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export const src = ''
|
||||||
|
export const url = ''
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
const params = new URLSearchParams(window.location.search)
|
||||||
|
export const src = params.get('ref_src') ?? ''
|
||||||
|
export const url = decodeURIComponent(params.get('ref_url') ?? '')
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import {nanoid} from 'nanoid/non-secure'
|
import {nanoid} from 'nanoid/non-secure'
|
||||||
|
|
||||||
|
import {Provider as GrowthbookProvider} from '#/logger/growthbook/context'
|
||||||
import {logEvent} from '#/lib/statsig/statsig'
|
import {logEvent} from '#/lib/statsig/statsig'
|
||||||
import {add} from '#/logger/logDump'
|
import {add} from '#/logger/logDump'
|
||||||
import {type MetricEvents} from '#/logger/metrics'
|
import {type MetricEvents} from '#/logger/metrics'
|
||||||
@@ -171,3 +172,10 @@ export class Logger {
|
|||||||
* `logger.error(error[, metadata])`
|
* `logger.error(error[, metadata])`
|
||||||
*/
|
*/
|
||||||
export const logger = Logger.create(Logger.Context.Default)
|
export const logger = Logger.create(Logger.Context.Default)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger context provider
|
||||||
|
*/
|
||||||
|
export function Provider({children}: {children: React.ReactNode}) {
|
||||||
|
return <GrowthbookProvider>{children}</GrowthbookProvider>
|
||||||
|
}
|
||||||
@@ -4678,6 +4678,20 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
nanoid "^3.3.1"
|
nanoid "^3.3.1"
|
||||||
|
|
||||||
|
"@growthbook/growthbook-react@^1.6.2":
|
||||||
|
version "1.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@growthbook/growthbook-react/-/growthbook-react-1.6.2.tgz#847135be0c46b167f980dbe6015e5f4ed010475c"
|
||||||
|
integrity sha512-96Bo2Jwd4NBn/kBLN4ceF299PhTw8fQltRykD32hu2xMW8/LXhB8swxbPshGK+Xfa2gjgt24kpZ5oSvaVLLT7w==
|
||||||
|
dependencies:
|
||||||
|
"@growthbook/growthbook" "^1.6.2"
|
||||||
|
|
||||||
|
"@growthbook/growthbook@^1.6.2":
|
||||||
|
version "1.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@growthbook/growthbook/-/growthbook-1.6.2.tgz#6a25122deac8a09955f6bddeb134af62b209809b"
|
||||||
|
integrity sha512-x3sK6Lff4BVusIzcdBeHZqA3B4kLs3kM/pJ7vvLTJwb6N/+Yn99EF1yc0XU6cfDVqFq6uFkvIFhMwDWUaKD73g==
|
||||||
|
dependencies:
|
||||||
|
dom-mutator "^0.6.0"
|
||||||
|
|
||||||
"@grpc/grpc-js@^1.8.20":
|
"@grpc/grpc-js@^1.8.20":
|
||||||
version "1.13.3"
|
version "1.13.3"
|
||||||
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.13.3.tgz#6ad08d186c2a8651697085f790c5c68eaca45904"
|
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.13.3.tgz#6ad08d186c2a8651697085f790c5c68eaca45904"
|
||||||
@@ -10522,6 +10536,11 @@ dom-converter@^0.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
utila "~0.4"
|
utila "~0.4"
|
||||||
|
|
||||||
|
dom-mutator@^0.6.0:
|
||||||
|
version "0.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/dom-mutator/-/dom-mutator-0.6.0.tgz#079d7a4b3e8981a562cd777548b99baab51d65c5"
|
||||||
|
integrity sha512-iCt9o0aYfXMUkz/43ZOAUFQYotjGB+GNbYJiJdz4TgXkyToXbbRy5S6FbTp72lRBtfpUMwEc1KmpFEU4CZeoNg==
|
||||||
|
|
||||||
dom-serializer@^1.0.1:
|
dom-serializer@^1.0.1:
|
||||||
version "1.4.1"
|
version "1.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
|
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
|
||||||
|
|||||||
Reference in New Issue
Block a user