1- import { ArrowPathIcon } from "@heroicons/react/24/outline" ;
2- import { useContext , useEffect , useState } from "react" ;
1+ import { CheckIcon } from "@heroicons/react/24/outline" ;
2+ import { useContext } from "react" ;
33import { Button } from "../.." ;
4+ import { useAuth } from "../../../context/Auth" ;
45import { IdeMessengerContext } from "../../../context/IdeMessenger" ;
5- import { getLocalStorage } from "../../../util/localStorage" ;
6+ import { useAppDispatch } from "../../../redux/hooks" ;
7+ import { selectFirstHubProfile } from "../../../redux/thunks/selectFirstHubProfile" ;
68import { useOnboardingCard } from "../hooks/useOnboardingCard" ;
79
810/**
9- * Models Add-On tab component displaying pricing and tier information
11+ * Models Add-On tab component with two-step onboarding:
12+ * 1. Create Account - Uses auth.login(true) to sign up and redirect back to IDE
13+ * 2. Purchase Credits - Opens /settings/billing to purchase credits
1014 */
1115export function OnboardingModelsAddOnTab ( ) {
1216 const ideMessenger = useContext ( IdeMessengerContext ) ;
1317 const { close } = useOnboardingCard ( ) ;
14- const [ isPolling , setIsPolling ] = useState ( false ) ;
18+ const auth = useAuth ( ) ;
19+ const dispatch = useAppDispatch ( ) ;
1520
16- const isJetbrains = getLocalStorage ( "ide" ) === "jetbrains" ;
21+ const isLoggedIn = ! ! auth . session ;
1722
18- // Polling effect for JetBrains
19- // This is because jetbrains doesn't support deeplinking the same way as VS Code
20- useEffect ( ( ) => {
21- if ( ! isPolling || ! isJetbrains ) return ;
22-
23- const interval = setInterval ( ( ) => {
24- ideMessenger . post ( "config/refreshProfiles" , {
25- reason : "Jetbrains onboarding polling" ,
26- selectProfileId : "local" ,
27- } ) ;
28- } , 7000 ) ;
29-
30- return ( ) => clearInterval ( interval ) ;
31- } , [ isPolling , isJetbrains , ideMessenger ] ) ;
32-
33- async function openBillingSettings ( ) {
34- try {
35- await ideMessenger . request ( "controlPlane/openUrl" , {
36- path : "settings/billing" ,
37- } ) ;
38- } catch ( error ) {
39- console . error ( "Error during upgrade process:" , error ) ;
40- } finally {
41- if ( isJetbrains ) {
42- setIsPolling ( true ) ;
43- } else {
44- close ( ) ;
23+ function handleCreateAccount ( ) {
24+ void auth . login ( true ) . then ( ( success ) => {
25+ if ( success ) {
26+ // A new assistant is created when the account is created
27+ // Switch to it immediately
28+ void dispatch ( selectFirstHubProfile ( ) ) ;
29+ ideMessenger . post ( "showToast" , [ "info" , "Account created!" ] ) ;
4530 }
46- }
31+ } ) ;
32+ }
33+
34+ function handlePurchaseCredits ( ) {
35+ ideMessenger . post ( "controlPlane/openUrl" , {
36+ path : "settings/billing" ,
37+ } ) ;
38+ close ( ) ;
4739 }
4840
4941 function openPricingPage ( ) {
@@ -52,28 +44,14 @@ export function OnboardingModelsAddOnTab() {
5244 } ) ;
5345 }
5446
55- // Show polling UI for JetBrains after upgrade
56- if ( isPolling && isJetbrains ) {
57- return (
58- < div className = "flex h-full w-full flex-col items-center justify-center text-center" >
59- < h2 className = "text-foreground mb-4 items-center text-lg font-semibold" >
60- < ArrowPathIcon className = "text-foreground animate-spin-slow mr-2 h-4 w-4" />
61- You may close this dialog after upgrading
62- </ h2 >
63- </ div >
64- ) ;
65- }
66-
6747 return (
6848 < div className = "flex h-full w-full flex-col items-center justify-center text-center" >
6949 < div className = "mb-4 flex flex-col items-center text-center" >
70- < div className = "mb-1" >
71- < h2 className = "text-foreground mb-1 text-2xl font-semibold" >
72- Models Add-on
73- </ h2 >
74- </ div >
50+ < h2 className = "text-foreground mb-1 text-2xl font-semibold" >
51+ Models Add-on
52+ </ h2 >
7553
76- < span className = "text-description text-base " >
54+ < span className = "text-description text-xs " >
7755 Use a{ " " }
7856 < span
7957 className = "cursor-pointer underline hover:brightness-125"
@@ -85,21 +63,67 @@ export function OnboardingModelsAddOnTab() {
8563 </ span >
8664 </ div >
8765
88- < div className = "w-full" >
89- < Button onClick = { openBillingSettings } className = "w-full max-w-xs" >
90- Purchase Credits
91- </ Button >
92- </ div >
93- < div className = "w-full text-center" >
94- < span className = "text-description" >
95- < span
96- className = "cursor-pointer underline hover:brightness-125"
97- onClick = { openPricingPage }
98- >
99- Click here
100- </ span > { " " }
101- to view pricing details
102- </ span >
66+ { /* Vertical step indicators */ }
67+ < div className = "flex w-full flex-col gap-4" >
68+ { /* Step 1: Create Account */ }
69+ < div className = "flex flex-col gap-2" >
70+ < div className = "flex items-center gap-2" >
71+ < div
72+ className = { `flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full text-xs font-medium ring-1 ring-inset ${
73+ isLoggedIn
74+ ? "bg-green-500 text-white ring-green-500"
75+ : "text-foreground ring-foreground bg-transparent"
76+ } `}
77+ >
78+ { isLoggedIn ? < CheckIcon className = "h-3 w-3" /> : "1" }
79+ </ div >
80+ < span
81+ className = { `text-sm ${ isLoggedIn ? "text-description" : "text-foreground font-medium" } ` }
82+ >
83+ Create Account
84+ </ span >
85+ </ div >
86+ < div className = "flex gap-2" >
87+ < div className = "w-5 flex-shrink-0" />
88+ < Button
89+ onClick = { handleCreateAccount }
90+ className = "flex-1"
91+ disabled = { isLoggedIn }
92+ >
93+ Create Account
94+ </ Button >
95+ </ div >
96+ </ div >
97+
98+ { /* Step 2: Purchase Credits */ }
99+ < div className = "flex flex-col gap-2" >
100+ < div className = "flex items-center gap-2" >
101+ < div
102+ className = { `flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full text-xs font-medium ring-1 ring-inset ${
103+ isLoggedIn
104+ ? "text-foreground ring-foreground bg-transparent"
105+ : "text-description ring-description bg-transparent"
106+ } `}
107+ >
108+ 2
109+ </ div >
110+ < span
111+ className = { `text-sm ${ isLoggedIn ? "text-foreground font-medium" : "text-description" } ` }
112+ >
113+ Purchase Credits
114+ </ span >
115+ </ div >
116+ < div className = "flex gap-2" >
117+ < div className = "w-5 flex-shrink-0" />
118+ < Button
119+ onClick = { handlePurchaseCredits }
120+ className = "flex-1"
121+ disabled = { ! isLoggedIn }
122+ >
123+ Purchase Credits
124+ </ Button >
125+ </ div >
126+ </ div >
103127 </ div >
104128 </ div >
105129 ) ;
0 commit comments