diff --git a/apps/x/apps/renderer/src/components/onboarding-modal.tsx b/apps/x/apps/renderer/src/components/onboarding-modal.tsx
index 3528d1ee..2080c52b 100644
--- a/apps/x/apps/renderer/src/components/onboarding-modal.tsx
+++ b/apps/x/apps/renderer/src/components/onboarding-modal.tsx
@@ -2,7 +2,8 @@
import * as React from "react"
import { useState, useEffect, useCallback } from "react"
-import { Loader2, Mic, Mail, CheckCircle2, MessageSquare } from "lucide-react"
+import { Loader2, Mic, Mail, CheckCircle2, ArrowLeft, MessageSquare } from "lucide-react"
+// import { MessageSquare } from "lucide-react"
import {
Dialog,
@@ -38,7 +39,7 @@ interface OnboardingModalProps {
onComplete: () => void
}
-type Step = 0 | 1 | 2 | 3
+type Step = 0 | 1 | 2 | 3 | 4
type OnboardingPath = 'rowboat' | 'byok' | null
@@ -367,11 +368,29 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
}, [])
const handleNext = () => {
- if (currentStep < 3) {
+ if (currentStep < 4) {
setCurrentStep((prev) => (prev + 1) as Step)
}
}
+ const handleBack = () => {
+ if (currentStep === 1) {
+ // BYOK upsell → back to sign-in page
+ setOnboardingPath(null)
+ setCurrentStep(0 as Step)
+ } else if (currentStep === 2) {
+ // LLM setup → back to BYOK upsell
+ setCurrentStep(1 as Step)
+ } else if (currentStep === 3) {
+ // Connect accounts → back depends on path
+ if (onboardingPath === 'rowboat') {
+ setCurrentStep(0 as Step)
+ } else {
+ setCurrentStep(2 as Step)
+ }
+ }
+ }
+
const handleComplete = () => {
onComplete()
}
@@ -486,11 +505,11 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
// Auto-advance from Rowboat sign-in step when OAuth completes
useEffect(() => {
- if (onboardingPath !== 'rowboat' || currentStep !== 1) return
+ if (onboardingPath !== 'rowboat' || currentStep !== 0) return
const cleanup = window.ipc.on('oauth:didConnect', (event) => {
if (event.provider === 'rowboat' && event.success) {
- setCurrentStep(2 as Step)
+ setCurrentStep(3 as Step)
}
})
@@ -568,20 +587,30 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
startConnect('google', clientId)
}, [startConnect])
- // Step indicator
- const renderStepIndicator = () => (
-
- {[0, 1, 2, 3].map((step) => (
-
= step ? "bg-primary" : "bg-muted"
- )}
- />
- ))}
-
- )
+ // Step indicator - dynamic based on path
+ const renderStepIndicator = () => {
+ // Rowboat path: Sign In (0), Connect (3), Done (4) = 3 dots
+ // BYOK path: Sign In (0), Upsell (1), Model (2), Connect (3), Done (4) = 5 dots
+ // Before path is chosen: show 3 dots (minimal)
+ const rowboatSteps = [0, 3, 4]
+ const byokSteps = [0, 1, 2, 3, 4]
+ const steps = onboardingPath === 'byok' ? byokSteps : rowboatSteps
+ const currentIndex = steps.indexOf(currentStep)
+
+ return (
+
+ {steps.map((_, i) => (
+
= i ? "bg-primary" : "bg-muted"
+ )}
+ />
+ ))}
+
+ )
+ }
// Helper to render an OAuth provider row
const renderOAuthProvider = (provider: string, displayName: string, icon: React.ReactNode, description: string) => {
@@ -788,55 +817,15 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
)
- // Step 0: Path Choice (Rowboat vs BYOK)
- const renderPathChoiceStep = () => (
-
-
- Your AI coworker, with memory
-
-
- Get Started
-
- Choose how you'd like to set up Rowboat
-
-
-
-
-
-
-
-
-
- )
-
- // Step 1 (Rowboat path): Sign in to Rowboat
- const renderRowboatSignInStep = () => {
+ // Step 0: Sign in to Rowboat (with BYOK option)
+ const renderSignInStep = () => {
const rowboatState = providerStates['rowboat'] || { isConnected: false, isLoading: false, isConnecting: false }
return (
+
+ Your AI coworker, with memory
+
Sign in to Rowboat
@@ -850,14 +839,17 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
Connected to Rowboat
-
) : (
startConnect('rowboat')}
+ onClick={() => {
+ setOnboardingPath('rowboat')
+ startConnect('rowboat')
+ }}
size="lg"
className="w-full"
disabled={rowboatState.isConnecting}
@@ -875,11 +867,73 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
)}
)}
+
+
+ {
+ setOnboardingPath('byok')
+ setCurrentStep(1 as Step)
+ }}
+ className="text-sm text-muted-foreground hover:text-foreground transition-colors"
+ >
+ Bring your own key
+
+
)
}
- // Step 1 (BYOK path): LLM Setup
+ // Step 1: BYOK upsell — explain benefits of Rowboat before continuing with BYOK
+ const renderByokUpsellStep = () => (
+
+
+ Before you continue
+
+ With a Rowboat account, you get:
+
+
+
+
+
+
+
+
Instant access to all models
+
GPT, Claude, Gemini, and more — no separate API keys needed
+
+
+
+
+
+
Simplified billing
+
One account for everything — no juggling multiple provider subscriptions
+
+
+
+
+
+
Automatic updates
+
New models are available as soon as they launch, with no configuration changes
+
+
+
+
+
+ By continuing, you'll set up your own API keys instead of using Rowboat's managed gateway.
+
+
+
+
+
+ Back
+
+
+ I understand
+
+
+
+ )
+
+ // Step 2 (BYOK path): LLM Setup
const renderLlmSetupStep = () => {
const primaryProviders: Array<{ id: LlmProviderFlavor; name: string; description: string }> = [
{ id: "openai", name: "OpenAI", description: "Use your OpenAI API key" },
@@ -1055,10 +1109,13 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
)}
-
+
+
+
+ Back
+
{testState.status === "testing" ? (
@@ -1072,7 +1129,7 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
)
}
- // Step 1: Connect Accounts
+ // Step 3: Connect Accounts
const renderAccountConnectionStep = () => (
@@ -1128,14 +1185,20 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
Continue
-
- Skip for now
-
+
+
+
+ Back
+
+
+ Skip for now
+
+
)
- // Step 2: Completion
+ // Step 4: Completion
const renderCompletionStep = () => {
const hasConnections = connectedProviders.length > 0 || granolaEnabled || slackEnabled || gmailConnected
@@ -1224,11 +1287,11 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) {
onEscapeKeyDown={(e) => e.preventDefault()}
>
{renderStepIndicator()}
- {currentStep === 0 && renderPathChoiceStep()}
- {currentStep === 1 && onboardingPath === 'rowboat' && renderRowboatSignInStep()}
- {currentStep === 1 && onboardingPath === 'byok' && renderLlmSetupStep()}
- {currentStep === 2 && renderAccountConnectionStep()}
- {currentStep === 3 && renderCompletionStep()}
+ {currentStep === 0 && renderSignInStep()}
+ {currentStep === 1 && renderByokUpsellStep()}
+ {currentStep === 2 && renderLlmSetupStep()}
+ {currentStep === 3 && renderAccountConnectionStep()}
+ {currentStep === 4 && renderCompletionStep()}
>