11"use client" ;
2+ import { Spinner } from "@/components/ui/Spinner/Spinner" ;
23import { Button } from "@/components/ui/button" ;
34import { Card , CardContent } from "@/components/ui/card" ;
45import { Checkbox } from "@/components/ui/checkbox" ;
@@ -27,8 +28,21 @@ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
2728import { RadioGroup } from "@radix-ui/react-radio-group" ;
2829import { THIRDWEB_ANALYTICS_API_HOST } from "constants/urls" ;
2930import { motion } from "framer-motion" ;
30- import { Users2 } from "lucide-react" ;
31- import { Building } from "lucide-react" ;
31+ import {
32+ Building ,
33+ Coins ,
34+ FileCode2 ,
35+ Fingerprint ,
36+ Gamepad2 ,
37+ Gift ,
38+ Landmark ,
39+ ListOrdered ,
40+ RectangleEllipsis ,
41+ ScanFace ,
42+ Users2 ,
43+ Wallet ,
44+ WalletCards ,
45+ } from "lucide-react" ;
3246import { useRouter } from "next/navigation" ;
3347import React from "react" ;
3448import { useState } from "react" ;
@@ -42,61 +56,78 @@ import { Blobbie } from "thirdweb/react";
4256import { shortenAddress } from "thirdweb/utils" ;
4357import { z } from "zod" ;
4458
59+ const iconSize = 24 ;
60+
4561const interestValues = [
4662 {
4763 key : "SOCIAL_LOGIN" ,
48- label : "Social Login " ,
64+ label : "Social Logins " ,
4965 description :
50- "Let users login to your app with Email, Phone, Telegram, and more" ,
66+ "Google, X, Discord, Farcaster, Telegram, Apple, and many more." ,
67+ icon : < RectangleEllipsis size = { iconSize } /> ,
5168 } ,
5269 {
5370 key : "WALLET_CONECTORS" ,
5471 label : "Wallet Connectors" ,
55- description : "Allow users to connect to over 350 web3 wallets" ,
72+ description : "Sign-in with any of the 350+ supported wallets." ,
73+ icon : < Wallet size = { iconSize } /> ,
74+ } ,
75+ {
76+ key : "INAPP_WALLETS" ,
77+ label : "In-App Wallets" ,
78+ description :
79+ "Create accounts securely with email, phone, social or passkey." ,
80+ icon : < WalletCards size = { iconSize } /> ,
5681 } ,
5782 {
5883 key : "SPONSOR_TRANSACTIONS" ,
5984 label : "Sponsor Transactions" ,
60- description :
61- "Abstract away signatures & gas using Account Abstraction and set up sponsorship rules" ,
85+ description : "Abstract away signatures & gas using Paymaster services." ,
86+ icon : < Gift size = { iconSize } /> ,
87+ } ,
88+ {
89+ key : "CONTRACT_DEPLOYS" ,
90+ label : "Deploy Contracts" ,
91+ description : "Deploy audited contracts to any EVM network" ,
92+ icon : < FileCode2 size = { iconSize } /> ,
6293 } ,
6394 {
6495 key : "UNIFIED_IDENTITY" ,
6596 label : "Unified Identity" ,
6697 description :
67- "Enable your users to link multiple onchain and offchain identities to a single ID" ,
98+ "Create a complete picture of all your users via identity linking." ,
99+ icon : < ScanFace size = { iconSize } /> ,
68100 } ,
69101 {
70102 key : "CUSTOM_AUTH" ,
71103 label : "Custom Auth" ,
72- description : "Authenticate with your backend using SIWE or JWT" ,
73- } ,
74- {
75- key : "QUERY_BLOCKCHAIN_DATA" ,
76- label : "Query Blockchain Data" ,
77- description : "All your data are belong to us" ,
104+ description : "Authenticate with your backend using SIWE or JWT." ,
105+ icon : < Fingerprint size = { iconSize } /> ,
78106 } ,
79107 {
80108 key : "AUTO_TXN_MGMT" ,
81109 label : "Automated Transaction Management" ,
82- description : "Scale transaction throughput with nonce management" ,
110+ description : "Read and write onchain at scale with unlimited throughput." ,
111+ icon : < ListOrdered size = { iconSize } /> ,
83112 } ,
84113 {
85114 key : "GAMING_TOOLS" ,
86115 label : "Gaming Tools" ,
87- description : "Everything you need to build a game" ,
116+ description :
117+ "SDKs to craft a seamless player experience and drive monetization." ,
118+ icon : < Gamepad2 size = { iconSize } /> ,
88119 } ,
89120 {
90121 key : "TOKEN_SWAPS" ,
91- label : "Token Swaps" ,
92- description :
93- "Bridge to and from tokens on any EVM, directly in your application" ,
122+ label : "Swaps & Bridging " ,
123+ description : "Bridge from hundreds of tokens across 20+ EVM chains." ,
124+ icon : < Coins size = { iconSize } /> ,
94125 } ,
95126 {
96127 key : "FIAT_ONRAMPS" ,
97- label : "Fiat Onramps " ,
98- description :
99- "Allow users to purchase with a credit card within your application." ,
128+ label : "Onramp Funds " ,
129+ description : "Enable fiat purchases to interact with your app." ,
130+ icon : < Landmark size = { iconSize } /> ,
100131 } ,
101132] ;
102133
@@ -165,6 +196,7 @@ export default function OnboardingPage({
165196 const accountQuery = useAccount ( ) ;
166197 const [ step , setStep ] = useState ( searchParams . email ? 2 : 1 ) ;
167198 const [ direction , setDirection ] = useState ( 1 ) ;
199+ const [ isLoading , setIsLoading ] = useState ( false ) ;
168200 const router = useRouter ( ) ;
169201
170202 const form = useForm < FormData > ( {
@@ -176,7 +208,7 @@ export default function OnboardingPage({
176208 } ) ;
177209
178210 const onSubmit : SubmitHandler < FormData > = async ( data ) => {
179- console . log ( data ) ;
211+ setIsLoading ( true ) ;
180212 const res = await fetch (
181213 `${ THIRDWEB_ANALYTICS_API_HOST } /v1/preferences/account` ,
182214 {
@@ -195,6 +227,7 @@ export default function OnboardingPage({
195227 } ) ,
196228 } ,
197229 ) ;
230+
198231 const json = await res . json ( ) ;
199232
200233 if ( res . status !== 200 ) {
@@ -259,7 +292,7 @@ export default function OnboardingPage({
259292 { step < 3 && (
260293 < Button
261294 type = "button"
262- variant = "secondary"
295+ variant = { "secondary" }
263296 onClick = { ( ) => {
264297 setDirection ( 1 ) ;
265298 setStep ( step + 1 ) ;
@@ -276,7 +309,7 @@ export default function OnboardingPage({
276309 { step === 3 && (
277310 < Button
278311 type = "button"
279- variant = "secondary "
312+ variant = "ghost "
280313 onClick = { ( ) => {
281314 setDirection ( - 1 ) ;
282315 setStep ( step - 1 ) ;
@@ -288,7 +321,7 @@ export default function OnboardingPage({
288321 { step === 3 && (
289322 < Button
290323 type = "submit"
291- variant = "primary"
324+ variant = { watchInterests . length > 0 ? "primary" : "secondary" }
292325 onClick = { form . handleSubmit ( onSubmit ) }
293326 >
294327 { watchInterests . length > 0 ? "Finish" : "Skip" }
@@ -326,10 +359,13 @@ export default function OnboardingPage({
326359 < FormControl >
327360 < Input
328361 className = "w-full min-w-[250px] sm:w-1/2"
329- { ...field }
330- id = "email"
331362 type = "email"
332363364+ { ...field }
365+ onBlur = { ( e ) => {
366+ e . preventDefault ( ) ;
367+ e . target . focus ( ) ;
368+ } }
333369 />
334370 </ FormControl >
335371 < FormMessage />
@@ -493,14 +529,14 @@ export default function OnboardingPage({
493529 ) ;
494530
495531 const Step3 : React . FC < StepProps > = ( { register } ) => (
496- < div className = "flex max-h-[450px ] flex-col space-y-4 overflow-scroll sm:max-h-[700px]" >
532+ < div className = "flex max-h-[550px ] flex-col space-y-4 overflow-scroll sm:max-h-[600px] md:max-h-[ 700px] lg:max-h-[750px ]" >
497533 < FormField
498534 name = "industry"
499535 control = { form . control }
500536 render = { ( ) => (
501537 < FormItem >
502538 < FormControl >
503- < div className = "grid w-full grid-cols-1 gap-6 xl:grid-cols-2 2xl:grid-cols-3" >
539+ < div className = "grid w-full grid-cols-1 gap-6 sm:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-3" >
504540 { interestValues . map ( ( interest ) => {
505541 const checkedInterests = watchInterests || [ ] ;
506542 const isChecked = checkedInterests . includes ( interest . key ) ;
@@ -509,7 +545,7 @@ export default function OnboardingPage({
509545 < Card
510546 key = { interest . key }
511547 className = { cn (
512- "no-scrollbar flex aspect-[2 .5/1] cursor-pointer flex-col items-start justify-start space-y-1 p-4 transition-colors hover:bg-muted md:aspect-[16/9]" ,
548+ "no-scrollbar flex aspect-[3 .5/1] cursor-pointer flex-col items-start justify-start space-y-1 p-4 transition-colors hover:bg-muted sm:aspect-[2/1] md:aspect-[16/9] lg:aspect-[4/3 ]" ,
513549 isChecked && "border-primary bg-muted" ,
514550 ) }
515551 onClick = { ( event ) => {
@@ -528,6 +564,7 @@ export default function OnboardingPage({
528564 { ...register ( "interests" ) }
529565 id = { `interest-${ interest . key } ` }
530566 />
567+ { interest . icon ?? null }
531568 < h5 className = "font-semibold text-lg tracking-tight" >
532569 { interest . label }
533570 </ h5 >
@@ -545,6 +582,21 @@ export default function OnboardingPage({
545582 </ div >
546583 ) ;
547584
585+ const Overlay = ( ) => {
586+ return (
587+ // biome-ignore lint/a11y/useKeyWithClickEvents: <explanation>
588+ < div
589+ className = "absolute z-50 flex h-screen w-screen flex-col items-center justify-center space-y-4 bg-[#00000088] text-center"
590+ onClick = { ( e ) => e . preventDefault ( ) }
591+ >
592+ < h4 className = "font-semibold text-2xl text-white" >
593+ Welcome to thirdweb!
594+ </ h4 >
595+ < Spinner className = "size-10 text-foreground" />
596+ </ div >
597+ ) ;
598+ } ;
599+
548600 const variants = {
549601 enter : { opacity : 0 , x : 200 * direction } ,
550602 center : { opacity : 1 , x : 0 } ,
@@ -559,6 +611,7 @@ export default function OnboardingPage({
559611
560612 return (
561613 < div className = "relative flex place-items-center bg-muted/30" >
614+ { isLoading ? < Overlay /> : null }
562615 < main className = "z-10 flex w-full flex-col-reverse gap-6 md:flex-row" >
563616 { /* Left Panel */ }
564617 < div className = "items-between relative box-border flex h-[80vh] w-full flex-col overflow-hidden p-4 md:h-screen md:w-1/2 md:p-12" >
0 commit comments