Skip to content

Commit 3fc6bd8

Browse files
committed
feat(ui): improve onboarding navigation and UX
- Replace Card with NavigationMenu for better layout - Set default plan to "Free Plan" with updated logic - Enhance step handling for backward navigation - Update stepper with dynamic text based on user state
1 parent d569bda commit 3fc6bd8

File tree

1 file changed

+69
-45
lines changed

1 file changed

+69
-45
lines changed

apps/ui/src/components/onboarding/onboarding-wizard.tsx

Lines changed: 69 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@ import { usePostHog } from "posthog-js/react";
66
import * as React from "react";
77
import { useState } from "react";
88

9-
import { Card, CardContent } from "@/lib/components/card";
9+
import {
10+
NavigationMenu,
11+
NavigationMenuItem,
12+
NavigationMenuList,
13+
} from "@/lib/components/navigation-menu";
1014
import { Stepper } from "@/lib/components/stepper";
1115
import { useApi } from "@/lib/fetch-client";
16+
import Logo from "@/lib/icons/Logo";
1217
import { useStripe } from "@/lib/stripe";
1318

14-
import { ApiKeyStep } from "./api-key-step";
1519
import { CreditsStep } from "./credits-step";
1620
import { PlanChoiceStep } from "./plan-choice-step";
1721
import { ProviderKeyStep } from "./provider-key-step";
@@ -27,16 +31,12 @@ const getSteps = (flowType: FlowType) => [
2731
},
2832
{
2933
id: "referral",
30-
title: "How did you hear about us?",
34+
title: "How did you find us?",
3135
optional: true,
3236
},
33-
{
34-
id: "api-key",
35-
title: "API Key",
36-
},
3737
{
3838
id: "plan-choice",
39-
title: "Choose Plan",
39+
title: "Choose your approach",
4040
},
4141
{
4242
id: flowType === "credits" ? "credits" : "provider-key",
@@ -48,10 +48,12 @@ const getSteps = (flowType: FlowType) => [
4848
export function OnboardingWizard() {
4949
const [activeStep, setActiveStep] = useState(0);
5050
const [flowType, setFlowType] = useState<FlowType>(null);
51-
const [hasSelectedPlan, setHasSelectedPlan] = useState(false);
51+
const [hasSelectedPlan, setHasSelectedPlan] = useState(true); // Free plan is selected by default
52+
const [selectedPlanName, setSelectedPlanName] = useState<string>("Free Plan"); // Free plan is default
5253
const [isPaymentSuccessful, setIsPaymentSuccessful] = useState(false);
5354
const [referralSource, setReferralSource] = useState<string>("");
5455
const [referralDetails, setReferralDetails] = useState<string>("");
56+
5557
const router = useRouter();
5658
const posthog = usePostHog();
5759
const { stripe, isLoading: stripeLoading } = useStripe();
@@ -65,10 +67,16 @@ export function OnboardingWizard() {
6567
const STEPS = getSteps(flowType);
6668

6769
const handleStepChange = async (step: number) => {
68-
// Special handling for plan choice step (now at index 3)
69-
if (activeStep === 3) {
70-
if (!hasSelectedPlan) {
71-
// Skip to dashboard if no plan selected
70+
// Handle backward navigation
71+
if (step < activeStep) {
72+
setActiveStep(step);
73+
return;
74+
}
75+
76+
// Special handling for plan choice step (now at index 2)
77+
if (activeStep === 2) {
78+
if (!hasSelectedPlan || flowType === null) {
79+
// Skip to dashboard if no plan selected or if continuing with free plan
7280
posthog.capture("onboarding_skipped", {
7381
skippedAt: "plan_choice",
7482
referralSource: referralSource || "not_provided",
@@ -103,26 +111,28 @@ export function OnboardingWizard() {
103111
const handleSelectCredits = () => {
104112
setFlowType("credits");
105113
setHasSelectedPlan(true);
106-
setActiveStep(4);
114+
setSelectedPlanName("Buy Credits");
115+
setActiveStep(3);
107116
};
108117

109118
const handleSelectBYOK = () => {
110119
setFlowType("byok");
111120
setHasSelectedPlan(true);
112-
setActiveStep(4);
121+
setSelectedPlanName("Bring Your Own Keys");
122+
setActiveStep(3);
113123
};
114124

115125
const handleReferralComplete = (source: string, details?: string) => {
116126
setReferralSource(source);
117127
if (details) {
118128
setReferralDetails(details);
119129
}
120-
setActiveStep(2); // Move to API Key step
130+
setActiveStep(2); // Move to Plan Choice step
121131
};
122132

123133
// Special handling for PlanChoiceStep to pass callbacks
124134
const renderCurrentStep = () => {
125-
if (activeStep === 3) {
135+
if (activeStep === 2) {
126136
return (
127137
<PlanChoiceStep
128138
onSelectCredits={handleSelectCredits}
@@ -133,7 +143,7 @@ export function OnboardingWizard() {
133143
}
134144

135145
// For credits step, wrap with Stripe Elements
136-
if (activeStep === 4 && flowType === "credits") {
146+
if (activeStep === 3 && flowType === "credits") {
137147
return stripeLoading ? (
138148
<div className="p-6 text-center">Loading payment form...</div>
139149
) : (
@@ -144,7 +154,7 @@ export function OnboardingWizard() {
144154
}
145155

146156
// For BYOK step
147-
if (activeStep === 4 && flowType === "byok") {
157+
if (activeStep === 3 && flowType === "byok") {
148158
return <ProviderKeyStep />;
149159
}
150160

@@ -157,24 +167,29 @@ export function OnboardingWizard() {
157167
return <ReferralStep onComplete={handleReferralComplete} />;
158168
}
159169

160-
if (activeStep === 2) {
161-
return <ApiKeyStep />;
162-
}
163-
164170
return null;
165171
};
166172

167173
// Customize stepper steps to show appropriate button text
168174
const getStepperSteps = () => {
169175
return STEPS.map((step, index) => ({
170176
...step,
171-
// Make plan choice step show Skip when no selection
172-
...(index === 3 &&
173-
!hasSelectedPlan && {
174-
customNextText: "Skip",
175-
}),
177+
// Welcome step shows dynamic text based on user state
178+
...(index === 0 && {
179+
customNextText: "Next: How did you hear about us?",
180+
}),
181+
// Referral step shows dynamic text based on user state
182+
...(index === 1 && {
183+
customNextText: "Next: Choose your approach",
184+
}),
185+
// Make plan choice step show dynamic text based on selected plan
186+
...(index === 2 && {
187+
customNextText: hasSelectedPlan
188+
? `Continue with ${selectedPlanName}`
189+
: "Skip",
190+
}),
176191
// Remove optional status from credits step when payment is successful
177-
...(index === 4 &&
192+
...(index === 3 &&
178193
flowType === "credits" &&
179194
isPaymentSuccessful && {
180195
optional: false,
@@ -183,22 +198,31 @@ export function OnboardingWizard() {
183198
};
184199

185200
return (
186-
<div className="container mx-auto max-w-3xl py-10">
187-
<Card>
188-
<CardContent className="p-6 sm:p-8">
189-
<Stepper
190-
steps={getStepperSteps()}
191-
activeStep={activeStep}
192-
onStepChange={handleStepChange}
193-
className="mb-6"
194-
nextButtonDisabled={
195-
activeStep === 4 && flowType === "credits" && !isPaymentSuccessful
196-
}
197-
>
198-
{renderCurrentStep()}
199-
</Stepper>
200-
</CardContent>
201-
</Card>
201+
<div className="container mx-auto px-4 py-10">
202+
<NavigationMenu className="mx-auto">
203+
<NavigationMenuList>
204+
<NavigationMenuItem asChild>
205+
<div className="flex items-center space-x-2">
206+
<Logo className="h-8 w-8 rounded-full text-black dark:text-white" />
207+
<span className="text-xl font-bold tracking-tight text-zinc-900 dark:text-white">
208+
LLM Gateway
209+
</span>
210+
</div>
211+
</NavigationMenuItem>
212+
</NavigationMenuList>
213+
</NavigationMenu>
214+
215+
<Stepper
216+
steps={getStepperSteps()}
217+
activeStep={activeStep}
218+
onStepChange={handleStepChange}
219+
className="mb-6"
220+
nextButtonDisabled={
221+
activeStep === 3 && flowType === "credits" && !isPaymentSuccessful
222+
}
223+
>
224+
{renderCurrentStep()}
225+
</Stepper>
202226
</div>
203227
);
204228
}

0 commit comments

Comments
 (0)