Skip to content

Commit 52336ca

Browse files
committed
Pass credits and show them in ui
1 parent e96fbec commit 52336ca

File tree

4 files changed

+58
-47
lines changed

4 files changed

+58
-47
lines changed

cli/src/components/ad-banner.tsx

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const AdBanner: React.FC<AdBannerProps> = ({ ad }) => {
2525
useEffect(() => {
2626
logger.info(
2727
{ adText: ad.adText?.substring(0, 50), hasClickUrl: !!ad.clickUrl },
28-
'[gravity] Rendering AdBanner'
28+
'[gravity] Rendering AdBanner',
2929
)
3030
}, [ad])
3131
const theme = useTheme()
@@ -58,6 +58,7 @@ export const AdBanner: React.FC<AdBannerProps> = ({ ad }) => {
5858
>
5959
{/* Horizontal divider line */}
6060
<text style={{ fg: theme.muted }}>{'─'.repeat(terminalWidth)}</text>
61+
{/* Top line: ad text + Ad label */}
6162
<box
6263
style={{
6364
width: '100%',
@@ -68,44 +69,51 @@ export const AdBanner: React.FC<AdBannerProps> = ({ ad }) => {
6869
alignItems: 'flex-start',
6970
}}
7071
>
71-
<box
72+
<text
7273
style={{
73-
flexDirection: 'column',
74+
fg: theme.foreground,
7475
flexShrink: 1,
7576
maxWidth: maxTextWidth,
7677
}}
7778
>
78-
<text
79-
style={{
80-
fg: theme.foreground,
81-
}}
82-
>
83-
{ad.adText}
84-
</text>
85-
<box style={{ flexDirection: 'row', gap: 2 }}>
86-
{ctaText && (
87-
<Button
88-
onClick={handleClick}
89-
onMouseOver={() => setIsLinkHovered(true)}
90-
onMouseOut={() => setIsLinkHovered(false)}
91-
>
92-
<text
93-
style={{
94-
fg: theme.name === 'light' ? '#ffffff' : theme.background,
95-
bg: isLinkHovered ? theme.link : theme.muted,
96-
}}
97-
>
98-
{` ${ctaText} `}
99-
</text>
100-
</Button>
101-
)}
102-
{domain && (
103-
<text style={{ fg: theme.muted }}>{domain}</text>
104-
)}
105-
</box>
106-
</box>
79+
{ad.adText}
80+
</text>
10781
<text style={{ fg: theme.muted, flexShrink: 0 }}>Ad</text>
10882
</box>
83+
{/* Bottom line: button, domain, credits */}
84+
<box
85+
style={{
86+
width: '100%',
87+
paddingLeft: 1,
88+
paddingRight: 1,
89+
flexDirection: 'row',
90+
flexWrap: 'wrap',
91+
columnGap: 2,
92+
alignItems: 'center',
93+
}}
94+
>
95+
{ctaText && (
96+
<Button
97+
onClick={handleClick}
98+
onMouseOver={() => setIsLinkHovered(true)}
99+
onMouseOut={() => setIsLinkHovered(false)}
100+
>
101+
<text
102+
style={{
103+
fg: theme.name === 'light' ? '#ffffff' : theme.background,
104+
bg: isLinkHovered ? theme.link : theme.muted,
105+
}}
106+
>
107+
{` ${ctaText} `}
108+
</text>
109+
</Button>
110+
)}
111+
{domain && <text style={{ fg: theme.muted }}>{domain}</text>}
112+
<box style={{ flexGrow: 1 }} />
113+
{ad.credits != null && ad.credits > 0 && (
114+
<text style={{ fg: theme.muted }}>+{ad.credits} credits</text>
115+
)}
116+
</box>
109117
</box>
110118
)
111119
}

cli/src/hooks/use-gravity-ad.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ const MAX_ADS_AFTER_ACTIVITY = 3 // Show up to 3 ads after last activity, then s
1515

1616
type AdMessage = { role: 'user' | 'assistant'; content: string }
1717

18-
// Ad response type (matches Gravity API response)
18+
// Ad response type (matches Gravity API response, credits added after impression)
1919
export type AdResponse = {
2020
adText: string
2121
title: string
2222
url: string
2323
favicon: string
2424
clickUrl: string
2525
impUrl: string
26-
payout: number
26+
credits?: number // Set after impression is recorded (in cents)
2727
}
2828

2929
/**
@@ -105,9 +105,10 @@ export const useGravityAd = (): GravityAdState => {
105105
// Fire impression via web API when ad changes (grants credits)
106106
useEffect(() => {
107107
if (ad?.impUrl && !impressionFiredRef.current.has(ad.impUrl)) {
108-
impressionFiredRef.current.add(ad.impUrl)
108+
const currentImpUrl = ad.impUrl
109+
impressionFiredRef.current.add(currentImpUrl)
109110
logger.info(
110-
{ impUrl: ad.impUrl, payout: ad.payout },
111+
{ impUrl: currentImpUrl },
111112
'[gravity] Recording ad impression',
112113
)
113114

@@ -126,7 +127,7 @@ export const useGravityAd = (): GravityAdState => {
126127
Authorization: `Bearer ${authToken}`,
127128
},
128129
body: JSON.stringify({
129-
impUrl: ad.impUrl,
130+
impUrl: currentImpUrl,
130131
}),
131132
})
132133
.then((res) => res.json())
@@ -136,6 +137,12 @@ export const useGravityAd = (): GravityAdState => {
136137
{ creditsGranted: data.creditsGranted },
137138
'[gravity] Ad impression credits granted',
138139
)
140+
// Update ad with credits from impression response
141+
setAd((currentAd) =>
142+
currentAd?.impUrl === currentImpUrl
143+
? { ...currentAd, credits: data.creditsGranted }
144+
: currentAd,
145+
)
139146
}
140147
})
141148
.catch((err) => {
@@ -183,7 +190,7 @@ export const useGravityAd = (): GravityAdState => {
183190
'Content-Type': 'application/json',
184191
Authorization: `Bearer ${authToken}`,
185192
},
186-
body: JSON.stringify({ messages: adMessages }),
193+
body: JSON.stringify({ messages: messageHistory }),
187194
})
188195

189196
if (!response.ok) {
@@ -199,12 +206,7 @@ export const useGravityAd = (): GravityAdState => {
199206

200207
logger.info(
201208
{
202-
hasAd: !!ad,
203-
adText: ad?.adText,
204-
title: ad?.title,
205-
clickUrl: ad?.clickUrl,
206-
impUrl: ad?.impUrl,
207-
payout: ad?.payout,
209+
ad,
208210
},
209211
'[gravity] Received ad response',
210212
)

web/src/app/api/v1/ads/_post.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,9 @@ export async function postAds(params: {
158158
)
159159
}
160160

161-
// Return complete ad to client (client will call /impression endpoint when displayed)
162-
return NextResponse.json({ ad })
161+
// Return ad to client without payout (credits will come from impression endpoint)
162+
const { payout: _payout, ...adWithoutPayout } = ad
163+
return NextResponse.json({ ad: adWithoutPayout })
163164
} catch (error) {
164165
logger.error(
165166
{

web/src/app/api/v1/ads/impression/_post.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ function generateImpressionOperationId(userId: string, impUrl: string): string {
6767

6868
const bodySchema = z.object({
6969
// Only impUrl needed - we look up the ad data from our database
70-
impUrl: z.string().url(),
70+
impUrl: z.url(),
7171
})
7272

7373
export async function postAdImpression(params: {

0 commit comments

Comments
 (0)