forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {createContext, useContext, useMemo} from 'react'
2
3import {useGate} from '#/lib/statsig/statsig'
4import {useLanguagePrefs} from '#/state/preferences/languages'
5import {useServiceConfigQuery} from '#/state/queries/service-config'
6import {useSession} from '#/state/session'
7import {IS_DEV} from '#/env'
8import {device} from '#/storage'
9
10type TrendingContext = {
11 enabled: boolean
12}
13
14type LiveNowContext = {
15 did: string
16 domains: string[]
17}[]
18
19const TrendingContext = createContext<TrendingContext>({
20 enabled: false,
21})
22TrendingContext.displayName = 'TrendingContext'
23
24const LiveNowContext = createContext<LiveNowContext>([])
25LiveNowContext.displayName = 'LiveNowContext'
26
27const CheckEmailConfirmedContext = createContext<boolean | null>(null)
28
29export function Provider({children}: {children: React.ReactNode}) {
30 const langPrefs = useLanguagePrefs()
31 const {data: config, isLoading: isInitialLoad} = useServiceConfigQuery()
32 const trending = useMemo<TrendingContext>(() => {
33 if (__DEV__) {
34 return {enabled: true}
35 }
36
37 /*
38 * Only English during beta period
39 */
40 if (
41 !!langPrefs.contentLanguages.length &&
42 !langPrefs.contentLanguages.includes('en')
43 ) {
44 return {enabled: false}
45 }
46
47 /*
48 * While loading, use cached value
49 */
50 const cachedEnabled = device.get(['trendingBetaEnabled'])
51 if (isInitialLoad) {
52 return {enabled: Boolean(cachedEnabled)}
53 }
54
55 /*
56 * Doing an extra check here to reduce hits to statsig. If it's disabled on
57 * the server, we can exit early.
58 */
59 const enabled = Boolean(config?.topicsEnabled)
60
61 // update cache
62 device.set(['trendingBetaEnabled'], enabled)
63
64 return {enabled}
65 }, [isInitialLoad, config, langPrefs.contentLanguages])
66
67 const liveNow = useMemo<LiveNowContext>(() => config?.liveNow ?? [], [config])
68
69 // probably true, so default to true when loading
70 // if the call fails, the query will set it to false for us
71 const checkEmailConfirmed = config?.checkEmailConfirmed ?? true
72
73 return (
74 <TrendingContext.Provider value={trending}>
75 <LiveNowContext.Provider value={liveNow}>
76 <CheckEmailConfirmedContext.Provider value={checkEmailConfirmed}>
77 {children}
78 </CheckEmailConfirmedContext.Provider>
79 </LiveNowContext.Provider>
80 </TrendingContext.Provider>
81 )
82}
83
84export function useTrendingConfig() {
85 return useContext(TrendingContext)
86}
87
88const DEFAULT_LIVE_ALLOWED_DOMAINS = [
89 'twitch.tv',
90 'www.twitch.tv',
91 'stream.place',
92]
93export type LiveNowConfig = {
94 allowedDomains: Set<string>
95}
96export function useLiveNowConfig(): LiveNowConfig {
97 const ctx = useContext(LiveNowContext)
98 const canGoLive = useCanGoLive()
99 const {currentAccount} = useSession()
100 if (!currentAccount?.did || !canGoLive) return {allowedDomains: new Set()}
101 const vip = ctx.find(live => live.did === currentAccount.did)
102 return {
103 allowedDomains: new Set(
104 DEFAULT_LIVE_ALLOWED_DOMAINS.concat(vip ? vip.domains : []),
105 ),
106 }
107}
108
109export function useCanGoLive() {
110 const gate = useGate()
111 const {hasSession} = useSession()
112 if (!hasSession) return false
113 return IS_DEV ? true : gate('live_now_beta')
114}
115
116export function useCheckEmailConfirmed() {
117 const ctx = useContext(CheckEmailConfirmedContext)
118 if (ctx === null) {
119 throw new Error(
120 'useCheckEmailConfirmed must be used within a ServiceConfigManager',
121 )
122 }
123 return ctx
124}