@@ -5,7 +5,7 @@ import { supabase } from "@/lib/supabase";
55import { v4 as uuidv4 } from "uuid" ;
66import { useEffect , useRef , useState } from "react" ;
77
8- import { Check , Clock } from "lucide-react" ;
8+ import { Check , Clock , Loader2 } from "lucide-react" ;
99import { Button } from "@/components/ui/button" ;
1010import { useRouter , useSearchParams } from "next/navigation" ;
1111import { UserSubscription } from "@/hooks/useAuth" ;
@@ -39,7 +39,7 @@ import {
3939 Kimi ,
4040} from "@lobehub/icons" ;
4141import { countries } from "@/lib/countries" ;
42- import { plans } from "@/lib/utils" ;
42+ import { cn , plans } from "@/lib/utils" ;
4343import { INDUSTRIES } from "@/lib/utils" ;
4444import ShinyText from "@/components/ui/shiny-text" ;
4545import { KeywordAnalysisResults } from "@/components/keywords/keyword-analysis-results" ;
@@ -71,12 +71,40 @@ type KeywordAnalysisResultsProps = {
7171 metadata : Array < { language : string ; country : string } > ;
7272} ;
7373
74+ type AutofillData = {
75+ logoUrl : string ;
76+ industry : string ;
77+ businessSubcategory : string ;
78+ brandVoice : string ;
79+ businessEntity : {
80+ type : string ;
81+ description : string ;
82+ offering : string ;
83+ } ;
84+ mainLanguage : string ;
85+ mainCountry : string ;
86+ otherCountries : string [ ] ;
87+ competitors : string [ ] ;
88+ brandName : string ;
89+ brandNameVariations : string [ ] ;
90+ brandWebsiteUrl : string ;
91+ brandCallToAction : string ;
92+ brandSocialMediaUrl : {
93+ linkedin : string ;
94+ youtube : string ;
95+ meta : string ;
96+ instagram : string ;
97+ x : string ;
98+ tiktok : string ;
99+ } ;
100+ } ;
101+
74102export default function OnboardingPage ( ) {
75103 const router = useRouter ( ) ;
76104 const searchParams = useSearchParams ( ) ;
77105 const email = searchParams . get ( "email" ) ;
78106 const domain = searchParams . get ( "domain" ) ;
79- const step = searchParams . get ( "step" ) ;
107+ const step = searchParams . get ( "step" ) || "0" ;
80108 const [ onboardingStep , setOnboardingStep ] = useState ( parseInt ( step ! ) ) ;
81109 const [ selectedPlan , setSelectedPlan ] = useState ( "" ) ;
82110 const [ password , setPassword ] = useState ( "" ) ;
@@ -105,6 +133,8 @@ export default function OnboardingPage() {
105133 const [ manualLanguage , setManualLanguage ] = useState ( "" ) ;
106134 const [ manualLocation , setManualLocation ] = useState ( "" ) ;
107135 const [ isManualAnalyzing , setIsManualAnalyzing ] = useState ( false ) ;
136+ const [ autofillData , setAutofillData ] = useState < AutofillData | null > ( null ) ;
137+ const [ isLoadingAutofill , setIsLoadingAutofill ] = useState ( false ) ;
108138
109139
110140 // Update time every second
@@ -250,6 +280,11 @@ export default function OnboardingPage() {
250280 setSessionKey ( authData . session ?. access_token || "" ) ;
251281 setOnboardingStep ( 1 ) ; // Move to brand creation
252282 toast . success ( "Account created! Now let's set up your brand." ) ;
283+
284+ // Fetch autofill data using domain from email
285+ if ( domain ) {
286+ await fetchAutofillData ( `${ domain } ` ) ;
287+ }
253288 }
254289 } catch ( error : unknown ) {
255290 const errorMessage =
@@ -266,6 +301,59 @@ export default function OnboardingPage() {
266301 setOnboardingStep ( ( prev ) => prev + 1 ) ;
267302 } ;
268303
304+ // Function to fetch autofill data from our API
305+ const fetchAutofillData = async ( websiteUrl : string ) => {
306+ if ( ! websiteUrl ) return ;
307+
308+ setIsLoadingAutofill ( true ) ;
309+ try {
310+ const response = await fetch ( "/api/onboarding-autofill" , {
311+ method : "POST" ,
312+ headers : {
313+ "Content-Type" : "application/json" ,
314+ } ,
315+ body : JSON . stringify ( {
316+ website : websiteUrl ,
317+ } ) ,
318+ } ) ;
319+
320+ const result = await response . json ( ) ;
321+
322+ if ( response . ok && result . success ) {
323+ setAutofillData ( result . data ) ;
324+ // Auto-fill form fields
325+ if ( result . data . brandName ) setBrandName ( result . data . brandName ) ;
326+ if ( result . data . brandWebsiteUrl ) setBrandWebsite ( result . data . brandWebsiteUrl ) ;
327+ if ( result . data . industry ) setBrandIndustry ( result . data . industry ) ;
328+ if ( result . data . mainCountry ) setBrandLocation ( result . data . mainCountry ) ;
329+ if ( result . data . mainLanguage ) {
330+ // Map full language names to language codes
331+ const languageMap : { [ key : string ] : string } = {
332+ "English" : "en" ,
333+ "Spanish" : "es" ,
334+ "French" : "fr" ,
335+ "German" : "de" ,
336+ "Italian" : "it" ,
337+ "Portuguese" : "pt" ,
338+ "Russian" : "ru"
339+ } ;
340+ setBrandLanguage ( languageMap [ result . data . mainLanguage ] || "en" ) ;
341+ }
342+ if ( result . data . logoUrl ) setBrandLogoPreview ( result . data . logoUrl ) ;
343+
344+ toast . success ( "Brand information auto-filled!" ) ;
345+ } else {
346+ console . error ( "Failed to fetch autofill data:" , result . error ) ;
347+ toast . error ( "Failed to auto-fill brand information" ) ;
348+ }
349+ } catch ( error ) {
350+ console . error ( "Error fetching autofill data:" , error ) ;
351+ toast . error ( "Failed to auto-fill brand information" ) ;
352+ } finally {
353+ setIsLoadingAutofill ( false ) ;
354+ }
355+ } ;
356+
269357 const handleSkip = ( ) => {
270358 if ( onboardingStep === 0 ) {
271359 setSelectedPlan ( "free" ) ;
@@ -667,8 +755,8 @@ export default function OnboardingPage() {
667755 </ div >
668756 </ div >
669757 ) : (
670- < div className = "max-w-md mx-auto mb-8 flex items-center justify-center" >
671- < div className = "sm:max-w-[500px] border-accent" >
758+ < div className = "max-w-xl mx-auto mb-8 flex flex-col items-center justify-center" >
759+ < div className = { cn ( "sm:max-w-[500px] border-accent transition-all duration-400" , isLoadingAutofill && "opacity-30 cursor-not-allowed pointer-events-none hidden" ) } >
672760 < div className = "space-y-4 w-full" >
673761 < div className = "grid gap-6" >
674762 < div className = "grid gap-2" >
@@ -840,13 +928,140 @@ export default function OnboardingPage() {
840928 { submitting ? "Creating..." : "Create Brand" }
841929 </ Button >
842930 </ div >
931+
932+ { /* Additional Information from Autofill */ }
933+ { ( isLoadingAutofill || autofillData ) && (
934+ < div className = "max-w-5xl w-full mx-auto mt-8 px-6 flex flex-col items-center justify-center" >
935+ { isLoadingAutofill ? (
936+ < div className = "text-center items-center gap-4 flex flex-col" >
937+ < Loader2 className = "animate-spin w-6 h-6 text-blue-500" />
938+ < p className = "text-gray-400 shiny-text" > Fetching brand information...</ p >
939+ </ div >
940+ ) : autofillData && (
941+ < div className = "space-y-6" >
942+ < h3 className = "text-xl font-semibold text-gray-200 mb-4" > Additional Brand Information</ h3 >
943+
944+ { /* Company Description */ }
945+ { autofillData . businessEntity ?. description && (
946+ < div >
947+ < h4 className = "text-sm font-medium text-gray-300 mb-2" > Company Description</ h4 >
948+ < p className = "text-gray-400 text-sm leading-relaxed" >
949+ { autofillData . businessEntity . description }
950+ </ p >
951+ </ div >
952+ ) }
953+
954+ { /* Social Media Links */ }
955+ { autofillData . brandSocialMediaUrl && Object . values ( autofillData . brandSocialMediaUrl ) . some ( url => url ) && (
956+ < div >
957+ < h4 className = "text-sm font-medium text-gray-300 mb-2" > Social Media</ h4 >
958+ < div className = "flex items-center justify-center flex-wrap gap-2" >
959+ { autofillData . brandSocialMediaUrl . linkedin && (
960+ < a
961+ href = { autofillData . brandSocialMediaUrl . linkedin }
962+ target = "_blank"
963+ rel = "noopener noreferrer"
964+ className = "bg-zinc-700 px-3 py-1 rounded-full text-xs text-blue-400 hover:bg-zinc-600 transition-colors"
965+ >
966+ LinkedIn
967+ </ a >
968+ ) }
969+ { autofillData . brandSocialMediaUrl . x && (
970+ < a
971+ href = { autofillData . brandSocialMediaUrl . x }
972+ target = "_blank"
973+ rel = "noopener noreferrer"
974+ className = "bg-zinc-700 px-3 py-1 rounded-full text-xs text-blue-400 hover:bg-zinc-600 transition-colors"
975+ >
976+ X (Twitter)
977+ </ a >
978+ ) }
979+ { autofillData . brandSocialMediaUrl . youtube && (
980+ < a
981+ href = { autofillData . brandSocialMediaUrl . youtube }
982+ target = "_blank"
983+ rel = "noopener noreferrer"
984+ className = "bg-zinc-700 px-3 py-1 rounded-full text-xs text-blue-400 hover:bg-zinc-600 transition-colors"
985+ >
986+ YouTube
987+ </ a >
988+ ) }
989+ { autofillData . brandSocialMediaUrl . meta && (
990+ < a
991+ href = { autofillData . brandSocialMediaUrl . meta }
992+ target = "_blank"
993+ rel = "noopener noreferrer"
994+ className = "bg-zinc-700 px-3 py-1 rounded-full text-xs text-blue-400 hover:bg-zinc-600 transition-colors"
995+ >
996+ Facebook
997+ </ a >
998+ ) }
999+ { autofillData . brandSocialMediaUrl . instagram && (
1000+ < a
1001+ href = { autofillData . brandSocialMediaUrl . instagram }
1002+ target = "_blank"
1003+ rel = "noopener noreferrer"
1004+ className = "bg-zinc-700 px-3 py-1 rounded-full text-xs text-blue-400 hover:bg-zinc-600 transition-colors"
1005+ >
1006+ Instagram
1007+ </ a >
1008+ ) }
1009+ { autofillData . brandSocialMediaUrl . tiktok && (
1010+ < a
1011+ href = { autofillData . brandSocialMediaUrl . tiktok }
1012+ target = "_blank"
1013+ rel = "noopener noreferrer"
1014+ className = "bg-zinc-700 px-3 py-1 rounded-full text-xs text-blue-400 hover:bg-zinc-600 transition-colors"
1015+ >
1016+ TikTok
1017+ </ a >
1018+ ) }
1019+ </ div >
1020+ </ div >
1021+ ) }
1022+
1023+ { /* Competitors */ }
1024+ { autofillData . competitors && autofillData . competitors . length > 0 && (
1025+ < div >
1026+ < h4 className = "text-sm font-medium text-gray-300 mb-2" > Competitors</ h4 >
1027+ < div className = "flex items-center justify-center flex-wrap gap-2" >
1028+ { autofillData . competitors . slice ( 0 , 8 ) . map ( ( competitor , index ) => (
1029+ < span
1030+ key = { index }
1031+ className = "bg-zinc-700 px-3 py-1 rounded-full text-xs text-gray-300"
1032+ >
1033+ { competitor }
1034+ </ span >
1035+ ) ) }
1036+ { autofillData . competitors . length > 8 && (
1037+ < span className = "bg-zinc-700 px-3 py-1 rounded-full text-xs text-gray-400" >
1038+ +{ autofillData . competitors . length - 8 } more
1039+ </ span >
1040+ ) }
1041+ </ div >
1042+ </ div >
1043+ ) }
1044+
1045+ { /* Brand Voice */ }
1046+ { autofillData . brandVoice && (
1047+ < div >
1048+ < h4 className = "text-sm font-medium text-gray-300 mb-2" > Brand Voice</ h4 >
1049+ < p className = "text-gray-400 text-sm leading-relaxed" >
1050+ { autofillData . brandVoice }
1051+ </ p >
1052+ </ div >
1053+ ) }
1054+ </ div >
1055+ ) }
1056+ </ div >
1057+ ) }
8431058 </ div >
8441059 ) }
8451060
8461061 < div className = "flex justify-between mt-8" >
8471062 < Button
8481063 variant = "ghost"
849- onClick = { ( ) => setOnboardingStep ( 1 ) }
1064+ onClick = { ( ) => setOnboardingStep ( 0 ) }
8501065 disabled = { isAnalyzing }
8511066 >
8521067 ← Back
0 commit comments