MCPcopy Index your code
hub / github.com/CodebuffAI/codebuff / useGravityAd

Function useGravityAd

cli/src/hooks/use-gravity-ad.ts:90–439  ·  view source on GitHub ↗
(options?: {
  enabled?: boolean
  /** Skip the "wait for first user message" gate. Used by the freebuff
   *  waiting room, which has no conversation but still needs ads. */
  forceStart?: boolean
  /** Ad network to request first. The server owns fallback ordering. */
  provider?: AdProvider
  /** Product surface requesting the ad. The server maps this to placements. */
  surface?: AdSurface
})

Source from the content-addressed store, hash-verified

88 * Activity is tracked via the global activity-tracker module.
89 */
90export const useGravityAd = (options?: {
91 enabled?: boolean
92 /** Skip the "wait for first user message" gate. Used by the freebuff
93 * waiting room, which has no conversation but still needs ads. */
94 forceStart?: boolean
95 /** Ad network to request first. The server owns fallback ordering. */
96 provider?: AdProvider
97 /** Product surface requesting the ad. The server maps this to placements. */
98 surface?: AdSurface
99}): GravityAdState => {
100 const enabled = options?.enabled ?? true
101 const forceStart = options?.forceStart ?? false
102 const provider: AdProvider = options?.provider ?? 'gravity'
103 const surface = options?.surface
104 const [ads, setAds] = useState<AdResponse[] | null>(null)
105 const [isLoading, setIsLoading] = useState(false)
106
107 // Check if terminal height is too small to show ads
108 const { terminalHeight } = useTerminalLayout()
109 const isVeryCompactHeight = terminalHeight <= 17
110
111 // Freebuff always shows ads even on compact screens (ads are mandatory there).
112 const isFreeMode = IS_FREEBUFF
113
114 // Skip ads on very compact screens unless we're in Freebuff (where ads are mandatory)
115 // Also skip if explicitly disabled (e.g. user has a subscription)
116 const shouldHideAds = !enabled || (isVeryCompactHeight && !isFreeMode)
117
118 // Use Zustand selector instead of manual subscription - only rerenders when value changes
119 const hasUserMessagedStore = useChatStore((s) =>
120 s.messages.some((m) => m.variant === 'user'),
121 )
122 // forceStart lets callers (e.g. the waiting room) opt out of the
123 // "wait for the first user message" gate.
124 const shouldStart = forceStart || hasUserMessagedStore
125
126 // Single consolidated controller ref
127 const ctrlRef = useRef<GravityController>({
128 choiceCache: [],
129 choiceCacheIndex: 0,
130 impressionsFired: new Set(),
131 adsShownSinceActivity: 0,
132 tickInFlight: false,
133 })
134
135 // Ref for the tick function (avoids useCallback dependency issues)
136 const tickRef = useRef<() => void>(() => {})
137
138 // Ref to track whether ads should be hidden for use in async code
139 const shouldHideAdsRef = useRef(shouldHideAds)
140 shouldHideAdsRef.current = shouldHideAds
141
142 // Fire impression and update credits (called when showing an ad)
143 const recordImpressionOnce = (ad: AdResponse): void => {
144 // Don't record impressions when ads should be hidden
145 if (shouldHideAdsRef.current) return
146
147 const ctrl = ctrlRef.current

Callers 2

ChatFunction · 0.90
WaitingRoomScreenFunction · 0.90

Calls 7

useTerminalLayoutFunction · 0.90
getAdsEnabledFunction · 0.90
isUserActiveFunction · 0.90
subscribeToActivityFunction · 0.90
fetchAdFunction · 0.85
addToChoiceCacheFunction · 0.85
nextFromChoiceCacheFunction · 0.85

Tested by

no test coverage detected