-
Notifications
You must be signed in to change notification settings - Fork 68
feat(ui): improve onboarding UX #945
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Updated the date format for the API key creation timestamp in the onboarding component to a more user-friendly format, enhancing readability.
Revised the development setup section to clarify the steps for starting required services, building packages, and setting up the database. Added notes for WSL2 users regarding Docker integration.
- Replace status column with inline badges for better space usage - Remove redundant "Keys" card wrapper on mobile for cleaner design - Fix mobile button placement to be full-width and below header - Remove redundant copy and simplify card descriptions - Use consistent badge styling across desktop and mobile views
- Updated layout to use flexbox for improved responsiveness - Separated desktop and mobile views for API keys display - Simplified card structure and descriptions for clarity - Ensured full-width button on mobile for better usability
- Revised guidance to specify AI agents instead of Claude Code - Added new commands for pushing and seeding the database - Corrected "LLMGateway" to "LLM Gateway" for consistency - Introduced folder structure section for better organization - Added license information and details on enterprise features
- Changed badge variant from "outline" to "secondary" for better visual distinction - Updated active status badge styles for improved readability and consistency across the UI
- Added StatusBadge component to standardize status display across API keys and provider keys lists - Replaced existing badge implementations with StatusBadge for improved consistency and styling
- Updated the development setup section to combine dependency installation and environment setup into a single command. - Clarified the steps for starting development servers and building for production. - Removed redundant steps for starting services and setting up the database, streamlining the process for users.
- Implemented a status filter for API keys, allowing users to view all, active, or inactive keys. - Added bulk activation functionality for inactive keys, enhancing user management capabilities. - Introduced Tabs and Tooltip components for improved UI interaction and information display. - Updated the API keys list to reflect the new filtering and activation features.
- Replaced the Plus icon with Orbit for a fresh look in the Create API Key button. - Enhanced the description text to clarify the purpose of API keys. - Adjusted the Card component layout for better spacing and visual appeal.
- Simplified header and description text for clarity. - Enhanced error handling for project loading status. - Improved layout for displaying existing API keys with mobile responsiveness. - Added Tooltip for displaying creation dates in a user-friendly format. - Updated card structure for newly created API keys to enhance visibility and organization.
- Added dynamic icons for different status states (active, inactive, default) using lucide-react. - Improved status text formatting for better readability. - Updated badge styling for a more consistent and visually appealing layout.
- Updated tooltip span in ApiKeysList and ApiKeyStep components to include a dotted underline and hover effect for improved user interaction and visual clarity.
- Added auto-switching between active and inactive tabs based on key availability. - Enhanced loading state handling and ensured active tab displays results after activation.
- Implemented a mobile layout featuring a compact circular progress indicator. - Improved accessibility and visual clarity with updated button and text styles. - Ensured step titles and optional indicators are displayed correctly across devices.
- Added loading and error states with spinner and retry - Redirect users to the login page only when not loading and no user data is available. - Wrap the OnboardingWizard with UserProvider
- Removed UserProvider and server-side data fetching for user data. - Updated OnboardingPage to directly render OnboardingClient, enhancing performance and reducing complexity.
- 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
- Add Credits, BYOK, and Enterprise plans with descriptions - Implement responsive grid layout for plan options - Detect self-hosting and update messaging accordingly - Add visual elements with icons and badges for plan states - Improve button interactions based on plan availability
- Adjusted the stepper component to use full width and centered layout for better responsiveness. - Removed optional label rendering for steps to simplify the UI. - Ensured consistent styling for active and completed steps with updated class names.
- Integrate API key creation/management into onboarding - Detect existing keys and handle authentication - Add loading states and clipboard copy functionality - Improve UI messaging for self-hosting status
- Auto-complete referral sources based on user selection - Update UI messaging and remove unnecessary buttons - Improve layout and styling for better responsiveness
❌ Preview Environment deleted from BunnyshellAvailable commands (reply to this comment):
|
WalkthroughRefactors onboarding into a client-driven flow with a UserProvider (loading/error states), restructures wizard and steps (adds "free", removes ApiKey step, auto-advances referral, data-driven plan chooser), enhances WelcomeStep API-key logic, updates fonts/globals and layout, narrows Stepper, adds AppConfig.contactEmail, tweaks husky hooks, and removes TwitterComponents prop. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant P as /onboarding Page
participant C as OnboardingClient
participant UP as UserProvider
participant W as OnboardingWizard
U->>P: Navigate to /onboarding
P->>C: Mount client component
C->>UP: Initialize user context
UP-->>C: { user, isLoading, error }
alt isLoading
C-->>U: Show spinner + "Loading..."
else error
C-->>U: Show error + Retry button
else no user
C->>U: Redirect to /login
else user
C->>W: Render OnboardingWizard
end
sequenceDiagram
autonumber
actor U as User
participant W as OnboardingWizard
participant R as ReferralStep
participant P as PlanChoiceStep
participant S as WelcomeStep
participant API as Backend
participant Nav as Router
U->>W: Start onboarding
W->>R: Render "How did you find us?"
R-->>W: Auto-complete selection -> advance
W->>P: Render plan chooser
P-->>W: set selectedPlanName (free|credits|byok)
W->>S: Render Welcome / API key status
rect rgba(230,245,255)
S->>API: Fetch existing API keys
alt no keys & create chosen
S->>API: Create API key
API-->>S: Return key
S->>API: Invalidate/refetch queries
S->>API: Complete onboarding
S->>Nav: Navigate to /dashboard
else keys exist or skipped
S->>API: Complete onboarding
S->>Nav: Navigate to /dashboard
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–90 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used📓 Path-based instructions (3)**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
apps/ui/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧬 Code graph analysis (2)apps/ui/src/components/onboarding/onboarding-wizard.tsx (2)
apps/ui/src/components/onboarding/plan-choice-step.tsx (4)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🔇 Additional comments (15)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Tip 🧪 Early access (models): enabledWe are currently testing Sonnet 4.5 code review models, which should lead to better review quality. However, this model may result in higher noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience. Note:
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.husky/commit-msg(1 hunks).husky/pre-commit(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- .husky/commit-msg
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-09-25T15:37:36.675Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-25T15:37:36.675Z
Learning: Always run `pnpm format` before committing; use `pnpm lint` to check without fixing
Applied to files:
.husky/pre-commit
📚 Learning: 2025-09-25T15:39:12.723Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: AGENTS.md:0-0
Timestamp: 2025-09-25T15:39:12.723Z
Learning: Run `pnpm test:unit` and `pnpm test:e2e` after adding features
Applied to files:
.husky/pre-commit
📚 Learning: 2025-09-25T15:39:12.723Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: AGENTS.md:0-0
Timestamp: 2025-09-25T15:39:12.723Z
Learning: Run `pnpm format` after code changes
Applied to files:
.husky/pre-commit
📚 Learning: 2025-09-25T15:37:36.675Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-25T15:37:36.675Z
Learning: Always use pnpm for package management
Applied to files:
.husky/pre-commit
📚 Learning: 2025-09-25T15:39:12.723Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: AGENTS.md:0-0
Timestamp: 2025-09-25T15:39:12.723Z
Learning: Run `pnpm build` to ensure production builds work
Applied to files:
.husky/pre-commit
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: build / run
- GitHub Check: lint / run
- GitHub Check: test / run
- GitHub Check: generate / run
- Moved fnm loading logic to the top of both commit-msg and pre-commit hooks for better clarity and consistency. - Ensured that the check for pnpm availability remains intact and functional.
- Introduced `isSelfHostedHost` to check if a hostname indicates a self-hosted environment. - Added `isSelfHostedEnvironment` to determine if the current environment is self-hosted based on `window.location.hostname`.
- Replaced manual localhost detection with `isSelfHostedEnvironment` utility for cleaner code. - Updated user messaging to reflect the Pro plan status in the onboarding step.
- Wrapped onboarding completion logic in a try-catch block to log errors without disrupting the user flow. - Ensured users remain on the current step if onboarding fails, improving overall user experience.
- Replaced manual localhost checks with `isSelfHostedEnvironment` utility for improved readability. - Updated dependencies in effect hooks to ensure proper data fetching and state management. - Cleaned up conditional rendering for API key status messages to enhance user experience.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.husky/commit-msg(1 hunks).husky/pre-commit(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-09-25T15:37:36.675Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-25T15:37:36.675Z
Learning: Always run `pnpm format` before committing; use `pnpm lint` to check without fixing
Applied to files:
.husky/commit-msg.husky/pre-commit
📚 Learning: 2025-09-25T15:39:12.723Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: AGENTS.md:0-0
Timestamp: 2025-09-25T15:39:12.723Z
Learning: Run `pnpm format` after code changes
Applied to files:
.husky/commit-msg.husky/pre-commit
📚 Learning: 2025-09-25T15:39:12.723Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: AGENTS.md:0-0
Timestamp: 2025-09-25T15:39:12.723Z
Learning: Run `pnpm build` to ensure production builds work
Applied to files:
.husky/pre-commit
📚 Learning: 2025-09-25T15:37:36.675Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-25T15:37:36.675Z
Learning: Always use pnpm for package management
Applied to files:
.husky/pre-commit
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: test / run
- GitHub Check: generate / run
- GitHub Check: build / run
- GitHub Check: lint / run
- Updated fnm loading logic to check for command availability before attempting to load the environment. - Ensured commit message file is properly quoted when passed to commitlint for better handling of filenames.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/ui/src/components/onboarding/onboarding-wizard.tsx (1)
42-45: Credits step can be skipped without payingWhen the user selects the Credits plan, the last step stays marked as optional, so the Stepper renders a “Skip” button. Clicking it jumps to completion and calls
/complete-onboardingeven though no payment succeeded. That lets users bypass the required purchase entirely. Make the credits step non-optional (and drop the optional override tied toisPaymentSuccessful) so the skip button never appears during the credits flow.{ id: flowType === "credits" ? "credits" : "provider-key", title: flowType === "credits" ? "Credits" : "Provider Key", - optional: true, + optional: flowType !== "credits", }, @@ - ...(index === 3 && - flowType === "credits" && - isPaymentSuccessful && { - optional: false, - }),Also applies to: 205-209
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
.husky/commit-msg(1 hunks).husky/pre-commit(1 hunks)apps/ui/src/components/onboarding/onboarding-wizard.tsx(8 hunks)apps/ui/src/components/onboarding/plan-choice-step.tsx(2 hunks)apps/ui/src/components/onboarding/welcome-step.tsx(1 hunks)apps/ui/src/lib/utils/self-host.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- .husky/pre-commit
- .husky/commit-msg
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Never useanyoras anyin this TypeScript project unless absolutely necessary
Always use top-levelimport; never userequireor dynamicimport()
Files:
apps/ui/src/lib/utils/self-host.tsapps/ui/src/components/onboarding/plan-choice-step.tsxapps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/components/onboarding/welcome-step.tsx
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/ui/**/*.{ts,tsx}: In the Next.js UI, usenext/linkfor links andnext/navigationrouter for programmatic navigation
Use cookies for user settings not stored in the database to ensure SSR compatibilityUse cookies for user settings not stored in the database to ensure SSR works
Files:
apps/ui/src/lib/utils/self-host.tsapps/ui/src/components/onboarding/plan-choice-step.tsxapps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/components/onboarding/welcome-step.tsx
{apps,packages}/**/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Always use top-level import; never use require() or dynamic import()
Files:
apps/ui/src/lib/utils/self-host.tsapps/ui/src/components/onboarding/plan-choice-step.tsxapps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/components/onboarding/welcome-step.tsx
apps/ui/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use next/link for links and next/navigation's router for programmatic navigation
Files:
apps/ui/src/lib/utils/self-host.tsapps/ui/src/components/onboarding/plan-choice-step.tsxapps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/components/onboarding/welcome-step.tsx
🧬 Code graph analysis (3)
apps/ui/src/components/onboarding/plan-choice-step.tsx (5)
apps/playground/src/lib/config.tsx (1)
useAppConfig(25-31)apps/ui/src/hooks/useOrganization.ts (1)
useDefaultOrganization(9-21)apps/ui/src/lib/utils/self-host.ts (1)
isSelfHostedEnvironment(25-30)apps/ui/src/lib/components/stepper.tsx (1)
Step(172-174)apps/ui/src/components/shared/upgrade-to-pro-dialog.tsx (1)
UpgradeToProDialog(24-38)
apps/ui/src/components/onboarding/onboarding-wizard.tsx (4)
apps/ui/src/components/onboarding/plan-choice-step.tsx (1)
PlanChoiceStep(33-295)apps/ui/src/lib/components/navigation-menu.tsx (3)
NavigationMenu(159-159)NavigationMenuList(160-160)NavigationMenuItem(161-161)apps/playground/src/components/ui/logo.tsx (1)
Logo(3-19)apps/ui/src/lib/components/stepper.tsx (1)
Stepper(24-165)
apps/ui/src/components/onboarding/welcome-step.tsx (4)
apps/ui/src/lib/auth-client.ts (1)
useAuth(20-33)apps/ui/src/hooks/useDefaultProject.ts (1)
useDefaultProject(3-35)apps/ui/src/lib/fetch-client.ts (1)
useApi(22-28)apps/ui/src/lib/utils/self-host.ts (1)
isSelfHostedEnvironment(25-30)
🔇 Additional comments (1)
apps/ui/src/components/onboarding/welcome-step.tsx (1)
283-285: Show skip CTA when at least one key existsThe skip button only renders when
existingKeys.apiKeys.length > 1, so a returning project with exactly one key never sees the CTA and must redo onboarding. This regresses the intended “skip when you already have a key” behavior noted earlier. Please switch the condition to>= 1.- {existingKeys?.apiKeys && - existingKeys.apiKeys.length > 1 && + {existingKeys?.apiKeys && + existingKeys.apiKeys.length >= 1 && !apiKey && (
- Eliminated fnm loading logic from commit-msg and pre-commit hooks for simplicity. - Removed pnpm availability checks, streamlining the hooks to focus on their primary functions.
- Replaced manual localhost detection with a direct check on the app configuration for improved clarity. - Cleaned up the onboarding components by removing the utility and related state management. - Enhanced conditional rendering for API key status messages to streamline user experience.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/ui/src/components/onboarding/onboarding-wizard.tsx (1)
99-111: Handle onboarding completion failures to avoid crashingWhen
handleStepChangefinishes the flow it awaitscompleteOnboarding.mutateAsyncwithout guarding failures. If that request rejects, the async handler throws, React treats it as an unhandled error, and the onboarding UI crashes. Wrap the mutation in try/catch (and surface feedback) before navigating.- if (step >= STEPS.length) { - posthog.capture("onboarding_completed", { - completedSteps: STEPS.map((step) => step.id), - flowType, - referralSource: referralSource || "not_provided", - referralDetails: referralDetails || undefined, - }); - - await completeOnboarding.mutateAsync({}); - const queryKey = api.queryOptions("get", "/user/me").queryKey; - await queryClient.invalidateQueries({ queryKey }); - router.push("/dashboard"); + if (step >= STEPS.length) { + posthog.capture("onboarding_completed", { + completedSteps: STEPS.map((step) => step.id), + flowType, + referralSource: referralSource || "not_provided", + referralDetails: referralDetails || undefined, + }); + + try { + await completeOnboarding.mutateAsync({}); + const queryKey = api.queryOptions("get", "/user/me").queryKey; + await queryClient.invalidateQueries({ queryKey }); + router.push("/dashboard"); + } catch (error) { + console.error("Failed to complete onboarding:", error); + return; + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
.husky/commit-msg(1 hunks).husky/pre-commit(1 hunks)apps/ui/src/components/onboarding/onboarding-wizard.tsx(8 hunks)apps/ui/src/components/onboarding/plan-choice-step.tsx(2 hunks)apps/ui/src/components/onboarding/welcome-step.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- .husky/commit-msg
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Never useanyoras anyin this TypeScript project unless absolutely necessary
Always use top-levelimport; never userequireor dynamicimport()
Files:
apps/ui/src/components/onboarding/welcome-step.tsxapps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/components/onboarding/plan-choice-step.tsx
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/ui/**/*.{ts,tsx}: In the Next.js UI, usenext/linkfor links andnext/navigationrouter for programmatic navigation
Use cookies for user settings not stored in the database to ensure SSR compatibilityUse cookies for user settings not stored in the database to ensure SSR works
Files:
apps/ui/src/components/onboarding/welcome-step.tsxapps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/components/onboarding/plan-choice-step.tsx
{apps,packages}/**/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Always use top-level import; never use require() or dynamic import()
Files:
apps/ui/src/components/onboarding/welcome-step.tsxapps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/components/onboarding/plan-choice-step.tsx
apps/ui/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use next/link for links and next/navigation's router for programmatic navigation
Files:
apps/ui/src/components/onboarding/welcome-step.tsxapps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/components/onboarding/plan-choice-step.tsx
🧠 Learnings (4)
📚 Learning: 2025-09-25T15:37:36.675Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-25T15:37:36.675Z
Learning: Always run `pnpm format` before committing; use `pnpm lint` to check without fixing
Applied to files:
.husky/pre-commit
📚 Learning: 2025-09-25T15:39:12.723Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: AGENTS.md:0-0
Timestamp: 2025-09-25T15:39:12.723Z
Learning: Run `pnpm build` to ensure production builds work
Applied to files:
.husky/pre-commit
📚 Learning: 2025-09-25T15:39:12.723Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: AGENTS.md:0-0
Timestamp: 2025-09-25T15:39:12.723Z
Learning: Run `pnpm format` after code changes
Applied to files:
.husky/pre-commit
📚 Learning: 2025-09-25T15:39:12.723Z
Learnt from: CR
PR: theopenco/llmgateway#0
File: AGENTS.md:0-0
Timestamp: 2025-09-25T15:39:12.723Z
Learning: Always use pnpm for package management
Applied to files:
.husky/pre-commit
🧬 Code graph analysis (3)
apps/ui/src/components/onboarding/welcome-step.tsx (4)
apps/ui/src/lib/auth-client.ts (1)
useAuth(20-33)apps/ui/src/hooks/useDefaultProject.ts (1)
useDefaultProject(3-35)apps/ui/src/lib/fetch-client.ts (1)
useApi(22-28)apps/playground/src/lib/config.tsx (1)
useAppConfig(25-31)
apps/ui/src/components/onboarding/onboarding-wizard.tsx (4)
apps/ui/src/components/onboarding/plan-choice-step.tsx (1)
PlanChoiceStep(32-289)apps/ui/src/lib/components/navigation-menu.tsx (3)
NavigationMenu(159-159)NavigationMenuList(160-160)NavigationMenuItem(161-161)apps/playground/src/components/ui/logo.tsx (1)
Logo(3-19)apps/ui/src/lib/components/stepper.tsx (1)
Stepper(24-165)
apps/ui/src/components/onboarding/plan-choice-step.tsx (4)
apps/playground/src/lib/config.tsx (1)
useAppConfig(25-31)apps/ui/src/hooks/useOrganization.ts (1)
useDefaultOrganization(9-21)apps/ui/src/lib/components/stepper.tsx (1)
Step(172-174)apps/ui/src/components/shared/upgrade-to-pro-dialog.tsx (1)
UpgradeToProDialog(24-38)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: build / run
- GitHub Check: generate / run
- GitHub Check: lint / run
- GitHub Check: test / run
🔇 Additional comments (2)
.husky/pre-commit (1)
1-2: Shebang and hook command look solid.Running
pnpm lint-stagedunder an explicit Bash shebang restores a working pre-commit hook with no extraneous setup. Looks good.apps/ui/src/components/onboarding/welcome-step.tsx (1)
279-281: Skip CTA should trigger for users with a single keyThe guard
existingKeys.apiKeys.length > 1hides the “Skip setup” CTA unless the user has at least two keys. A user who already has exactly one key (the common case) can no longer exit onboarding, which is a regression. Please relax the condition to cover>= 1.- {existingKeys?.apiKeys && - existingKeys.apiKeys.length > 1 && + {existingKeys?.apiKeys && + existingKeys.apiKeys.length >= 1 &&
| buttonText: "Contact Sales", | ||
| buttonVariant: "outline" as const, | ||
| buttonDisabled: false, | ||
| onClick: () => window.open(`mailto:${config.contactEmail}`, "_blank"), | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fallback contact email is required
If config.contactEmail is undefined (misconfigured env, self-hosted tenants), the Enterprise CTA opens mailto:undefined, breaking the contact path. Add a sensible default to keep the link valid.
- onClick: () => window.open(`mailto:${config.contactEmail}`, "_blank"),
+ onClick: () =>
+ window.open(
+ `mailto:${config.contactEmail ?? "[email protected]"}`,
+ "_blank",
+ ),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| buttonText: "Contact Sales", | |
| buttonVariant: "outline" as const, | |
| buttonDisabled: false, | |
| onClick: () => window.open(`mailto:${config.contactEmail}`, "_blank"), | |
| }, | |
| buttonText: "Contact Sales", | |
| buttonVariant: "outline" as const, | |
| buttonDisabled: false, | |
| onClick: () => | |
| window.open( | |
| `mailto:${config.contactEmail ?? "[email protected]"}`, | |
| "_blank", | |
| ), | |
| }, |
🤖 Prompt for AI Agents
In apps/ui/src/components/onboarding/plan-choice-step.tsx around lines 124 to
128, the Enterprise CTA builds a mailto link with config.contactEmail which can
be undefined; change the onClick handler to use a sensible fallback email (e.g.
'[email protected]' or a project-wide SUPPORT_EMAIL constant) so the mailto
URL is always valid, e.g. use (config.contactEmail || '[email protected]')
when constructing the link; ensure the fallback value is documented or pulled
from a central config constant rather than hard-coded inline.
- Removed unused prop from for clarity. - Streamlined error handling in by adjusting indentation for better readability.
- Added free option to FlowType for onboarding steps. - Enhanced handleSelectFreePlan function to complete onboarding directly for the free plan. - Integrated analytics tracking for onboarding completion with the free plan. - Improved error handling during onboarding completion process.
- Reformatted font-family declarations in body and code for better clarity. - Ensured consistent indentation and spacing throughout the CSS file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/ui/src/components/onboarding/onboarding-wizard.tsx (1)
76-97: Good skip handling at plan choice; consider null-safe PostHog calls.Skip flow correctly completes onboarding and routes to the dashboard. However, use optional chaining on PostHog to avoid a runtime crash when the provider isn’t initialized.
Apply this diff for null-safety:
- posthog.capture("onboarding_skipped", { + posthog?.capture("onboarding_skipped", { skippedAt: "plan_choice", referralSource: referralSource || "not_provided", referralDetails: referralDetails || undefined, });Also applies to: 86-93
apps/ui/src/lib/components/tweet-card.tsx (1)
228-249: Stop leaking non-DOM props to the DOM; type and filter forwarded props.
TweetCardforwards...props(fromTweetProps) intoMagicTweet, which spreads them onto a<div>. Props likeapiUrl/fetchOptionswill end up as invalid DOM attributes, causing React warnings and noisy markup. Also,MagicTweet’s...propsisn’t typed for DOM attributes.Fix by:
- Typing
MagicTweetto acceptReact.HTMLAttributes<HTMLDivElement>.- Narrowing what
TweetCardforwards toMagicTweet(only DOM attrs + className), keeping react‑tweet props internal.Apply this diff:
@@ export const MagicTweet = ({ tweet, className, - ...props -}: { - tweet: Tweet; - className?: string; -}) => { + ...divProps +}: React.HTMLAttributes<HTMLDivElement> & { + tweet: Tweet; + className?: string; +}) => { const enrichedTweet = enrichTweet(tweet); return ( <div className={cn( "relative flex w-full h-64 max-w-lg flex-col gap-2 overflow-hidden rounded-lg border p-4 backdrop-blur-md", className, )} - {...props} + {...divProps} > <TweetHeader tweet={enrichedTweet} /> <TweetBody tweet={enrichedTweet} /> </div> ); }; @@ -export const TweetCard = async ({ - id, - components, - fallback = <TweetSkeleton />, - onError, - ...props -}: TweetProps & { - className?: string; -}) => { +type TweetCardProps = (TweetProps & { className?: string }) & + React.HTMLAttributes<HTMLDivElement>; + +export const TweetCard = async ({ + id, + components, + fallback = <TweetSkeleton />, + onError, + className, + ...divProps +}: TweetCardProps) => { @@ if (!tweet) { const NotFound = components?.TweetNotFound || TweetNotFound; - return <NotFound {...props} />; + return <NotFound className={className} {...divProps} />; } return ( <Suspense fallback={fallback}> - <MagicTweet tweet={tweet} {...props} /> + <MagicTweet tweet={tweet} className={className} {...divProps} /> </Suspense> ); }Also applies to: 279-281
🧹 Nitpick comments (6)
apps/ui/src/components/onboarding/onboarding-wizard.tsx (3)
99-112: Wrap final completion in try/catch to avoid dead-ends on failure.If completeOnboarding rejects here, the user is stuck with no feedback. Align error handling with the skip and free flows.
Apply this diff:
- posthog.capture("onboarding_completed", { + posthog?.capture("onboarding_completed", { completedSteps: STEPS.map((step) => step.id), flowType, referralSource: referralSource || "not_provided", referralDetails: referralDetails || undefined, }); - - await completeOnboarding.mutateAsync({}); - const queryKey = api.queryOptions("get", "/user/me").queryKey; - await queryClient.invalidateQueries({ queryKey }); - router.push("/dashboard"); + try { + await completeOnboarding.mutateAsync({}); + const queryKey = api.queryOptions("get", "/user/me").queryKey; + await queryClient.invalidateQueries({ queryKey }); + router.push("/dashboard"); + } catch (err) { + console.error("Failed to complete onboarding:", err); + }
175-183: Guard against missing Stripe instance.If stripeLoading is false but stripe is null, Elements will error. Add a fallback UI.
Apply this diff:
- if (activeStep === 3 && flowType === "credits") { - return stripeLoading ? ( + if (activeStep === 3 && flowType === "credits") { + return stripeLoading ? ( <div className="p-6 text-center">Loading payment form...</div> - ) : ( - <Elements stripe={stripe}> - <CreditsStep onPaymentSuccess={() => setIsPaymentSuccessful(true)} /> - </Elements> - ); + ) : !stripe ? ( + <div className="p-6 text-center">Unable to initialize payment. Please retry.</div> + ) : ( + <Elements stripe={stripe}> + <CreditsStep onPaymentSuccess={() => setIsPaymentSuccessful(true)} /> + </Elements> + );
230-242: Optional: Make brand header clickable to home.Wrap the logo/title in a Link to “/” with an aria-label for better UX/accessibility.
Proposed change:
+import Link from "next/link"; ... - <NavigationMenuItem asChild> - <div className="flex items-center space-x-2"> - <Logo className="h-8 w-8 rounded-full text-black dark:text-white" /> - <span className="text-xl font-bold tracking-tight text-zinc-900 dark:text-white"> - LLM Gateway - </span> - </div> - </NavigationMenuItem> + <NavigationMenuItem asChild> + <Link href="/" aria-label="Go to home" className="flex items-center space-x-2"> + <Logo className="h-8 w-8 rounded-full text-black dark:text-white" /> + <span className="text-xl font-bold tracking-tight text-zinc-900 dark:text-white"> + LLM Gateway + </span> + </Link> + </NavigationMenuItem>apps/ui/src/lib/components/tweet-card.tsx (3)
278-282: Suspense fallback is a no-op after awaiting getTweet.Because
getTweet(id)is awaited before render, there’s nothing insideSuspensethat can suspend. Consider removingSuspense(or moving fetch inside a child that can suspend) to simplify.- return ( - <Suspense fallback={fallback}> - <MagicTweet tweet={tweet} className={className} {...divProps} /> - </Suspense> - ); + return <MagicTweet tweet={tweet} className={className} {...divProps} />;
213-219: Avoid ts-ignore by narrowing optional card thumbnail access.Replace the ts-ignore with safe optional chaining and a tiny extractor to satisfy TS without suppressions.
- // @ts-ignore - tweet?.card?.binding_values?.thumbnail_image_large?.image_value.url && ( + (() => { + const url = + (tweet as unknown as { + card?: { + binding_values?: { + thumbnail_image_large?: { + image_value?: { url?: string }; + }; + }; + }; + })?.card?.binding_values?.thumbnail_image_large?.image_value?.url; + return url; + })() && ( <img - src={ - // @ts-ignore - tweet.card.binding_values.thumbnail_image_large.image_value.url - } + src={ + (tweet as any).card.binding_values.thumbnail_image_large + .image_value.url + } className="h-64 rounded-xl border object-cover shadow-sm" alt={tweet.text} /> )}Note: If tolerating a single
as anyis unacceptable here, extract a typed helper function. Based on learnings.
104-111: Minor a11y: make avatar alt more descriptive.Use the display name for clarity.
- alt={tweet.user.screen_name} + alt={`Avatar of ${tweet.user.name}`}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/ui/src/app/globals.css(4 hunks)apps/ui/src/components/onboarding/onboarding-wizard.tsx(8 hunks)apps/ui/src/lib/components/tweet-card.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Never useanyoras anyin this TypeScript project unless absolutely necessary
Always use top-levelimport; never userequireor dynamicimport()
Files:
apps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/lib/components/tweet-card.tsx
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/ui/**/*.{ts,tsx}: In the Next.js UI, usenext/linkfor links andnext/navigationrouter for programmatic navigation
Use cookies for user settings not stored in the database to ensure SSR compatibilityUse cookies for user settings not stored in the database to ensure SSR works
Files:
apps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/lib/components/tweet-card.tsx
{apps,packages}/**/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Always use top-level import; never use require() or dynamic import()
Files:
apps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/lib/components/tweet-card.tsx
apps/ui/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use next/link for links and next/navigation's router for programmatic navigation
Files:
apps/ui/src/components/onboarding/onboarding-wizard.tsxapps/ui/src/lib/components/tweet-card.tsx
🧠 Learnings (2)
📚 Learning: 2025-09-22T18:29:26.374Z
Learnt from: smakosh
PR: theopenco/llmgateway#911
File: apps/ui/src/lib/components/tweet-card.tsx:244-255
Timestamp: 2025-09-22T18:29:26.374Z
Learning: In the tweet-card component at apps/ui/src/lib/components/tweet-card.tsx, the TweetMedia component is intentionally not used in the MagicTweet component. This is a deliberate design decision to keep testimonials text-focused without rendering images or videos from tweets.
Applied to files:
apps/ui/src/lib/components/tweet-card.tsx
📚 Learning: 2025-09-22T18:30:31.975Z
Learnt from: smakosh
PR: theopenco/llmgateway#911
File: apps/ui/src/lib/components/tweet-card.tsx:170-174
Timestamp: 2025-09-22T18:30:31.975Z
Learning: In the tweet-card component at apps/ui/src/lib/components/tweet-card.tsx, the use of dangerouslySetInnerHTML for rendering tweet entity text is acceptable. The react-tweet library content is considered safe to render as HTML in this context.
Applied to files:
apps/ui/src/lib/components/tweet-card.tsx
🧬 Code graph analysis (1)
apps/ui/src/components/onboarding/onboarding-wizard.tsx (4)
apps/api/src/posthog.ts (1)
posthog(3-6)apps/ui/src/components/onboarding/plan-choice-step.tsx (1)
PlanChoiceStep(32-289)apps/playground/src/components/ui/logo.tsx (1)
Logo(3-19)apps/ui/src/lib/components/stepper.tsx (1)
Stepper(24-165)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: build / run
- GitHub Check: test / run
- GitHub Check: generate / run
- GitHub Check: lint / run
🔇 Additional comments (16)
apps/ui/src/components/onboarding/onboarding-wizard.tsx (15)
9-13: LGTM: Header navigation import is appropriate for the new onboarding header.
25-25: LGTM: FlowType now includes "free".
34-34: LGTM: Updated step titles improve clarity.Also applies to: 39-40
52-52: LGTM: Track selectedPlanName with a safe default.
70-75: LGTM: Backward navigation handled safely.
119-121: LGTM: Credits path sets plan state and advances to payment.
126-128: LGTM: BYOK path sets plan state and advances to provider key step.
130-152: Free plan now completes onboarding directly — resolved prior issue.This addresses the earlier bug where selecting Free left users on an empty step. Good job finishing the flow and invalidating cache before redirect.
Apply the same PostHog null-safety here:
- posthog.capture("onboarding_completed", { + posthog?.capture("onboarding_completed", { completedSteps: ["welcome", "referral", "plan-choice"], flowType: "free", referralSource: referralSource || "not_provided", referralDetails: referralDetails || undefined, });
159-159: LGTM: Referral completion advances to plan choice.
164-171: LGTM: PlanChoiceStep wiring includes Free, Credits, and BYOK handlers.
186-187: LGTM: BYOK step renders ProviderKeyStep at the correct index.
206-219: LGTM: Dynamic next button labels improve guidance; good use of selectedPlanName.
221-226: LGTM: Making credits step non-optional after success prevents accidental skip.
244-254: LGTM: Stepper props and nextButtonDisabled logic are correct for credits flow.
16-16: Logo default export confirmed — no action requiredapps/ui/src/lib/components/tweet-card.tsx (1)
2-2: Import change LGTM; confirm compatibility with remaining usage.Removing
TwitterComponentsfrom imports is fine.TweetCardstill consumescomponentsfromTweetPropsonly to overrideTweetNotFound, which is consistent. Verify no other local usage depended onTwitterComponents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/ui/src/app/globals.css (1)
11-30: Add fallbacks to the Geist font variablesIf
--font-geist-sansor--font-geist-monoever go missing (e.g., layout wiring regresses), the entirefont-familydeclaration becomes invalid and the UI drops to the browser default serif. Wrapping the full stack in the variable fallback keeps the intended system stack as a safety net.- font-family: - var(--font-geist-sans), - -apple-system, - BlinkMacSystemFont, - "Segoe UI", - "Roboto", - "Oxygen", - "Ubuntu", - "Cantarell", - "Fira Sans", - "Droid Sans", - "Helvetica Neue", - sans-serif; + font-family: + var( + --font-geist-sans, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + "Roboto", + "Oxygen", + "Ubuntu", + "Cantarell", + "Fira Sans", + "Droid Sans", + "Helvetica Neue", + sans-serif + ); @@ - font-family: - var(--font-geist-mono), source-code-pro, Menlo, Monaco, Consolas, - "Courier New", monospace; + font-family: + var( + --font-geist-mono, + source-code-pro, + Menlo, + Monaco, + Consolas, + "Courier New", + monospace + );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/ui/src/app/globals.css(6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: build / run
- GitHub Check: generate / run
- GitHub Check: test / run
- GitHub Check: lint / run
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/ui/src/app/globals.css (1)
48-49: Light theme destructive-foreground equals background — contrast bug
--destructiveand--destructive-foregroundare identical, making text/icons invisible on destructive surfaces.- --destructive: oklch(0.577 0.245 27.325); - --destructive-foreground: oklch(0.577 0.245 27.325); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.985 0 0);
🧹 Nitpick comments (6)
apps/ui/src/app/globals.css (6)
29-30: Add fallback for var(--font-geist-mono)Prevents property invalidation if the custom property isn’t set.
- var(--font-geist-mono), source-code-pro, Menlo, Monaco, Consolas, + var(--font-geist-mono, ui-monospace), source-code-pro, Menlo, Monaco, Consolas,
141-143: Harden animation tokens with defaultsProvide defaults for --duration to avoid invalid animation values when unset.
- --animate-marquee: marquee var(--duration) infinite linear; - --animate-marquee-vertical: marquee-vertical var(--duration) linear infinite; + --animate-marquee: marquee var(--duration, 30s) linear infinite; + --animate-marquee-vertical: marquee-vertical var(--duration, 30s) linear infinite;
144-152: Default --gap in marquee to avoid invalid transformsEnsures keyframes remain valid even if --gap isn’t set.
- transform: translateX(calc(-100% - var(--gap))); + transform: translateX(calc(-100% - var(--gap, 0px)));
154-162: Default --gap for vertical marquee as well- transform: translateY(calc(-100% - var(--gap))); + transform: translateY(calc(-100% - var(--gap, 0px)));
166-168: Extend base reset to ::before/::after (and box-sizing)Covers pseudo-elements and sets border-box universally, matching common Tailwind/shadcn resets.
-* { - @apply border-border outline-ring/50; - } +*, +*::before, +*::after { + @apply border-border outline-ring/50; + box-sizing: border-box; + }
174-192: Respect prefers-reduced-motion for marquee/accordion animationsOffer an accessible path for users who prefer reduced motion.
Add this block (placement near animations is fine):
@media (prefers-reduced-motion: reduce) { .animate-accordion-down, .animate-accordion-up { animation: none !important; } /* If you expose utilities using the --animate-* tokens, noop them */ .animate-marquee, .animate-marquee-vertical { animation: none !important; } }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/ui/src/app/globals.css(5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: test / run
- GitHub Check: build / run
- GitHub Check: generate / run
- GitHub Check: lint / run
- Added missing font options to the body font-family declaration for better typography. - Refactored layout.tsx to improve HTML structure by moving className to the <html> tag and simplifying the <body> tag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/ui/src/app/globals.css (1)
31-34: Harden thecodefont fallbackLine 32 uses
var(--font-geist-mono)without an inline fallback; if that custom property ever goes missing (bad deploy, alternate layout, etc.) the entirefont-familydeclaration becomes invalid and we lose the curated monospace stack. Please include a fallback inside thevar()so we gracefully degrade.- var(--font-geist-mono), source-code-pro, Menlo, Monaco, Consolas, + var(--font-geist-mono, source-code-pro), Menlo, Monaco, Consolas,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/ui/src/app/globals.css(5 hunks)apps/ui/src/app/layout.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Never useanyoras anyin this TypeScript project unless absolutely necessary
Always use top-levelimport; never userequireor dynamicimport()
Files:
apps/ui/src/app/layout.tsx
apps/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/ui/**/*.{ts,tsx}: In the Next.js UI, usenext/linkfor links andnext/navigationrouter for programmatic navigation
Use cookies for user settings not stored in the database to ensure SSR compatibilityUse cookies for user settings not stored in the database to ensure SSR works
Files:
apps/ui/src/app/layout.tsx
{apps,packages}/**/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Always use top-level import; never use require() or dynamic import()
Files:
apps/ui/src/app/layout.tsx
apps/ui/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use next/link for links and next/navigation's router for programmatic navigation
Files:
apps/ui/src/app/layout.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: build / run
- GitHub Check: lint / run
- GitHub Check: test / run
- GitHub Check: generate / run
| { | ||
| id: "api-key", | ||
| title: "API Key", | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why was this removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Welcome step automatically makes the key or shows how many they have. Immediate reward and reduces the steps. Its something you'd have to try to see if it makes sense to you or not.
Welcome Step
- Auto-generates API keys for new users
- Detects self-hosting vs hosted context
- Shows existing API key status with copy button
- Skip option for users with existing keys
- Better error handling with retry
Changed "Choose your approach" to "Choose plan" in both the onboarding wizard and plan choice step for consistency and clarity.
Overview
Streamlines the onboarding flow, adds auto-complete features, and improves the plan selection interface.
Key Changes
Visual & Typography
User Experience
Welcome Step
Referral Step
Plan Choice
Technical
Navigation & Flow
State Management
Code Quality
Files Changed
apps/ui/src/app/globals.css- Added Geist font variablesapps/ui/src/app/layout.tsx- Integrated Geist fontsapps/ui/src/app/onboarding/onboarding-client.tsx- Better loading/error statesapps/ui/src/app/onboarding/page.tsx- Simplified page structureapps/ui/src/components/onboarding/onboarding-wizard.tsx- Major UX improvementsapps/ui/src/components/onboarding/plan-choice-step.tsx- Complete redesignapps/ui/src/components/onboarding/referral-step.tsx- Auto-complete functionalityapps/ui/src/components/onboarding/welcome-step.tsx- API key management integrationapps/ui/src/lib/components/stepper.tsx- Layout improvementsTesting
Breaking Changes
None - this is purely additive and improves existing functionality.
Migration Notes
No migration required. All changes are backward compatible.
Commit History:
907edb4- Merge branch 'main' into fix/onboarding1505d20- fix(ui): update onboarding wizard text9bdccfd- feat(ui): add auto-complete to referral step1dd3eda- feat(ui): add API key management to welcome stepa88f9b2- fix(ui): improve stepper layout and stylingc784606- feat(ui): improve plan choice step with new features3fc6bd8- feat(ui): improve onboarding navigation and UXd569bda- refactor(ui): simplify onboarding page by removing UserProvidere9d5760- feat(ui): enhance onboarding UX2a5ddd6- feat(ui): add Geist fontsSummary by CodeRabbit
New Features
Style
Chores