Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { DocsCallout, DocsCard, DocsGrid, DocsPage, DocsSection } from '../docs/
>
<DocsGrid>
<DocsCard title="S1 – Disconnected">Setup tab with connect CTA; Buy Credits, Manage, and History tabs visible but disabled until a wallet connects.</DocsCard>
<DocsCard title="S1b – Setup tab">Connected wallet — static onboarding shell for Download AntSeed, Signer Key, and Authorize Wallet (step interactions are follow-up work).</DocsCard>
<DocsCard title="S1b – Setup tab">Connected wallet — setup onboarding starts with a Download AntSeed VPR/Desktop action, followed by locked Signer Key and Authorize Wallet steps.</DocsCard>
<DocsCard title="S2 – Purchase Setup">Buy tab — stepper with a CTA to open the active step in a bottom drawer.</DocsCard>
<DocsCard title="S3 – Quote Ready">Buy tab — pay step available via drawer CTA; ready to confirm Celo transaction.</DocsCard>
<DocsCard title="S4 – Payment Pending">Buy tab — Celo tx submitted.</DocsCard>
Expand All @@ -60,7 +60,7 @@ import { DocsCallout, DocsCard, DocsGrid, DocsPage, DocsSection } from '../docs/
description="Setup, Buy Credits, Manage, and History appear as tabs (with the GoodDollar header and chain badge). Before a wallet connects, only Setup is active. After connecting, switch tabs anytime — including during payment pending or failed states."
>
<DocsGrid>
<DocsCard title="Setup">Onboarding entry point — connect wallet when disconnected; onboarding step shell when connected.</DocsCard>
<DocsCard title="Setup">Onboarding entry point — connect wallet when disconnected; Download AntSeed VPR/Desktop action appears first once connected.</DocsCard>
<DocsCard title="Buy Credits">Stepper for buyer key, consent, and pay — tap a step or CTA to open it in a drawer.</DocsCard>
<DocsCard title="Manage">Credits balance, stream info, close/withdraw, and API setup.</DocsCard>
<DocsCard title="History">Paginated credit history with source, status, and date filters.</DocsCard>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ export const MultiBuyerHistory: Story = {

export const SetupTab: Story = {
render: () => <SetupTabStory />,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement)
const root = canvas.getByTestId('AiCreditsWidget-setup-tab')
const downloadLink = within(root).getByRole('link', { name: /download antseed vpr\/desktop/i })

await expect(downloadLink).toHaveAttribute(
'href',
'https://github.com/AntSeed/antseed/releases/latest',
)
},
}

export const AppKitConnectWallet: Story = {
Expand Down
45 changes: 2 additions & 43 deletions packages/ai-credits-widget/src/AiCreditsWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
SetupGuidanceCard,
HowToUseView,
SetupFaqView,
SetupOnboardingPanel,
} from './components'
import type {
AiCreditsWidgetProps,
Expand Down Expand Up @@ -87,24 +88,6 @@ function SetupConnectPrompt({
)
}

const SETUP_ONBOARDING_STEPS: Array<{ number: number; title: string; description: string }> = [
{
number: 1,
title: 'Download AntSeed',
description: 'Install the AntSeed application to manage your AI credits signer key.',
},
{
number: 2,
title: 'Signer Key',
description: 'Generate or import a signer key that AntSeed will use to authorize requests.',
},
{
number: 3,
title: 'Authorize Wallet',
description: 'Link your wallet to the signer key so it can be topped up with AI credits.',
},
]

function SetupTabPanel({
state,
onConnect,
Expand All @@ -126,31 +109,7 @@ function SetupTabPanel({
<Heading level={5} secondary>
Onboarding
</Heading>
{SETUP_ONBOARDING_STEPS.map((step) => (
<Card key={step.number}>
<XStack gap="$3" alignItems="flex-start" padding="$3">
<YStack
width={28}
height={28}
borderRadius={14}
backgroundColor="$primary"
alignItems="center"
justifyContent="center"
flexShrink={0}
>
<Text fontWeight="700" fontSize="$2" color="$onPrimary">
{step.number}
</Text>
</YStack>
<YStack flex={1} gap="$1">
<Text fontWeight="700">{step.title}</Text>
<Text secondary fontSize="$2">
{step.description}
</Text>
</YStack>
</XStack>
</Card>
))}
<SetupOnboardingPanel />
</YStack>
)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/ai-credits-widget/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export { HistoryTab } from './history/HistoryTab'
export { SetupGuidanceCard } from './setup/SetupGuidanceCard'
export { HowToUseView } from './setup/HowToUseView'
export { SetupFaqView } from './setup/SetupFaqView'
export { SetupOnboardingPanel } from './setup/SetupOnboardingPanel'
export type { AiCreditsFlowStep } from './flow/types'
export { getAiCreditsActiveFlowStep } from './flow/purchaseFlowUtils'
export { AiCreditsFlowStepper } from './flow/AiCreditsFlowStepper'
export { AiCreditsPurchaseFlow } from './flow/AiCreditsPurchaseFlow'

Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react'
import {
Anchor,
Button,
ButtonText,
Card,
Icon,
Stepper,
Text,
YStack,
} from '@goodwidget/ui'
import type { StepperStepItem } from '@goodwidget/ui'

/** Stable fallback download target for AntSeed VPR/Desktop installers. */
const ANTSEED_VPR_DOWNLOAD_URL = 'https://github.com/AntSeed/antseed/releases/latest'

const SETUP_ONBOARDING_STEPS: StepperStepItem[] = [
{
id: 'download-antseed',
title: 'Download AntSeed',
description: 'Install the desktop app that runs your credits locally.',
status: 'ready',
},
{
id: 'signer-key',
title: 'Signer Key',
status: 'pending',
},
{
id: 'authorize-wallet',
title: 'Authorize Wallet',
status: 'pending',
},
]

/**
* Setup-only onboarding shell. This slice exposes the AntSeed desktop download
* action while leaving the later Signer Key / Authorize Wallet setup work
* locked behind the first step.
*/
export function SetupOnboardingPanel() {
return (
<YStack gap="$4" width="100%">
<Text secondary>One-time setup, in order — each step unlocks the next.</Text>

<Stepper steps={SETUP_ONBOARDING_STEPS} activeStepId="download-antseed" maxHeight={280} />

<Card gap="$3" padding="$4">
<YStack gap="$2">
<Text fontWeight="700">Download AntSeed VPR/Desktop</Text>
<Text secondary>
Install AntSeed before generating your signer key. It runs your AI credits locally and
only needs to be installed once on each computer.
</Text>
</YStack>

<Anchor
href={ANTSEED_VPR_DOWNLOAD_URL}
target="_blank"
rel="noopener noreferrer"
style={{ textDecorationLine: 'none' }}
>
<Button width="100%" gap="$2">
<Icon name="external-link" size="xs" color="primary" />
<ButtonText>Download AntSeed VPR/Desktop</ButtonText>
</Button>
</Anchor>

<Text fontSize="$1" secondary>
Opens the latest AntSeed desktop release in a new tab.
</Text>
</Card>
</YStack>
)
}
5 changes: 5 additions & 0 deletions tests/widgets/ai-credits-widget/states.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,14 @@ test('AiCreditsWidget Setup tab — onboarding steps visible', async ({ page })
await gotoStory(page, STORY_IDS.setupTab)
const root = page.getByTestId('AiCreditsWidget-setup-tab')
await expect(root).toBeVisible()
const downloadLink = root.getByRole('link', { name: /download antseed vpr\/desktop/i })
await expect(root.getByText('Download AntSeed', { exact: true })).toBeVisible()
await expect(root.getByText('Signer Key', { exact: true })).toBeVisible()
await expect(root.getByText('Authorize Wallet', { exact: true })).toBeVisible()
await expect(downloadLink).toHaveAttribute(
'href',
'https://github.com/AntSeed/antseed/releases/latest',
)
await expect(root.getByText('Setup', { exact: true })).toBeVisible()
await expect(root.getByText('Buy Credits', { exact: true })).toBeVisible()
await page.screenshot({
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.