@@ -2,7 +2,7 @@ import { ENDPOINTS, fetcher } from "@api/useAxiosSWR";
22import { EMAIL_PATTERN } from "@constants/index" ;
33import { AxiosError } from "axios" ;
44import { enqueueSnackbar } from "notistack" ;
5- import { useState } from "react" ;
5+ import { useState , useEffect } from "react" ;
66import { useForm } from "react-hook-form" ;
77import PhoneInput from "react-phone-input-2" ;
88
@@ -34,53 +34,132 @@ const SignUpForm = ({ toggleSignUp }: Props) => {
3434 const [ signing , setSigning ] = useState ( false ) ;
3535 const [ progress , setProgress ] = useState ( 0 ) ;
3636 const [ stepMessage , setStepMessage ] = useState ( "Initializing..." ) ;
37-
38- const updateProgress = ( value : number , message : string ) => {
37+ const [ currentStep , setCurrentStep ] = useState ( 0 ) ;
38+
39+ // Define signup process steps
40+ const signupSteps = [
41+ { title : "Validating Information" , description : "Checking your details..." } ,
42+ { title : "Creating Account" , description : "Setting up your profile..." } ,
43+ { title : "Configuring Site" , description : "Preparing your workspace..." } ,
44+ { title : "Finalizing Setup" , description : "Almost there..." } ,
45+ { title : "Ready!" , description : "Redirecting to your dashboard..." } ,
46+ ] ;
47+
48+ const updateProgress = ( value : number , message : string , step : number = - 1 ) => {
49+ console . log ( `Progress update: ${ value } % - ${ message } ` ) ;
3950 setProgress ( value ) ;
4051 setStepMessage ( message ) ;
52+ if ( step >= 0 ) {
53+ setCurrentStep ( step ) ;
54+ } else {
55+ // Calculate step based on progress
56+ const newStep = Math . min ( Math . floor ( value / 20 ) , 4 ) ;
57+ setCurrentStep ( newStep ) ;
58+ }
4159 } ;
4260
4361 const onSubmit = async ( data : Record < string , string > ) => {
62+ console . log ( "Form submission started with data:" , data ) ;
4463 setSigning ( true ) ;
45- updateProgress ( 10 , "Starting signup..." ) ;
64+ updateProgress ( 5 , "Starting signup process ..." , 0 ) ;
4665
4766 try {
48- updateProgress ( 20 , "Sending signup request..." ) ;
49- const response : any = await fetcher . post ( ENDPOINTS . signup , { ...data } ) ;
50-
51- updateProgress ( 40 , "Received response from server..." ) ;
67+ // Step 1: Validate data
68+ await new Promise ( resolve => setTimeout ( resolve , 800 ) ) ; // Simulate validation time
69+ updateProgress ( 20 , "Validating your information..." , 0 ) ;
70+ console . log ( "Sending signup request to:" , ENDPOINTS . signup ) ;
71+
72+ // Step 2: Create account
73+ updateProgress ( 40 , "Creating your account..." , 1 ) ;
74+ await new Promise ( resolve => setTimeout ( resolve , 800 ) ) ; // Simulate account creation time
75+
76+ const response : any = await fetcher . post ( ENDPOINTS . signup , { ...data } )
77+ . catch ( error => {
78+ console . error ( "API request failed:" , error ) ;
79+ console . log ( "Error response data:" , error . response ?. data ) ;
80+ console . log ( "Error status:" , error . response ?. status ) ;
81+ throw error ;
82+ } ) ;
83+
84+ console . log ( "Signup API response received:" , response ) ;
85+
86+ // Step 3: Configure site
87+ updateProgress ( 60 , "Setting up your site..." , 2 ) ;
88+ await new Promise ( resolve => setTimeout ( resolve , 800 ) ) ; // Simulate site setup time
5289
5390 const token = response ?. token ?? response ?. message ?. token ?? null ;
5491 const site_url = response ?. site_url ?? response ?. message ?. site_url ?? null ;
5592
56- updateProgress ( 70 , "Validating site creation..." ) ;
93+ console . log ( "Extracted token:" , token ? "Token exists" : "Token missing" ) ;
94+ console . log ( "Extracted site_url:" , site_url ) ;
95+
96+ // Step 4: Finalize
97+ updateProgress ( 80 , "Finalizing your workspace..." , 3 ) ;
98+ await new Promise ( resolve => setTimeout ( resolve , 800 ) ) ; // Simulate finalization time
5799
58100 if ( token && site_url ) {
101+ console . log ( "Signup successful, proceeding to redirect" ) ;
59102 enqueueSnackbar ( `🎉 Site created! Welcome to AlphaX, ${ data . email } ` , { variant : "success" } ) ;
60103 localStorage . setItem ( "access_token" , token ) ;
61104 reset ( ) ;
62105
63- updateProgress ( 100 , "Redirecting to your new site..." ) ;
106+ // Step 5: Ready
107+ updateProgress ( 100 , "Redirecting to your new site..." , 4 ) ;
108+ console . log ( "Will redirect to:" , site_url ) ;
64109 setTimeout ( ( ) => {
65110 window . location . href = site_url ;
66- } , 1000 ) ;
111+ } , 1500 ) ;
67112 } else {
113+ console . warn ( "Signup completed but token or site_url is missing" , { token, site_url } ) ;
68114 updateProgress ( 100 , "⚠️ Site was not created." ) ;
69115 enqueueSnackbar ( "Site was not created. Please try again later." , { variant : "warning" } ) ;
70116 }
71117 } catch ( error ) {
118+ console . error ( "Signup process error:" , error ) ;
119+
120+ // Log detailed error information
121+ if ( ( error as AxiosError ) . isAxiosError ) {
122+ const axiosError = error as AxiosError ;
123+ console . error ( "Axios error details:" , {
124+ status : axiosError . response ?. status ,
125+ statusText : axiosError . response ?. statusText ,
126+ data : axiosError . response ?. data ,
127+ headers : axiosError . response ?. headers ,
128+ } ) ;
129+ }
130+
72131 const errorMessage =
73132 ( ( error as AxiosError ) ?. response ?. data as { message : string } ) ?. message ||
74133 ( error as Error ) . message ||
75134 "Internal error. Please try again later" ;
76135
136+ console . error ( "Error message to display:" , errorMessage ) ;
77137 enqueueSnackbar ( errorMessage , { variant : "error" } ) ;
78138 updateProgress ( 100 , "Something went wrong." ) ;
79139 } finally {
80- setSigning ( false ) ;
140+ console . log ( "Signup process completed" ) ;
141+ // We don't set signing to false here to keep the modal visible if redirecting
81142 }
82143 } ;
83144
145+ // This effect will automatically animate progress bar smoothly
146+ useEffect ( ( ) => {
147+ if ( signing && progress < 100 ) {
148+ const interval = setInterval ( ( ) => {
149+ setProgress ( prev => {
150+ // Increment progress slightly for animation effect
151+ const target = Math . min ( ( currentStep + 1 ) * 20 , 100 ) ;
152+ if ( prev < target - 2 ) {
153+ return prev + 0.5 ;
154+ }
155+ clearInterval ( interval ) ;
156+ return prev ;
157+ } ) ;
158+ } , 50 ) ;
159+ return ( ) => clearInterval ( interval ) ;
160+ }
161+ } , [ signing , progress , currentStep ] ) ;
162+
84163 return (
85164 < div className = "hide-scrollbar w-full h-screen overflow-auto bg-gray-50 dark:bg-gray-900 p-4 flex justify-center items-center" >
86165 < div className = "hide-scrollbar w-full max-w-[700px] bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl shadow-sm overflow-y-auto max-h-full" >
@@ -180,6 +259,9 @@ const SignUpForm = ({ toggleSignUp }: Props) => {
180259 />
181260 < span className = "ml-2 mt-3 text-gray-500 text-sm" > .alphaxerp.com</ span >
182261 </ div >
262+ { formErrors . siteName && (
263+ < p className = "text-xs text-red-600 mt-2" > { formErrors . siteName . message } </ p >
264+ ) }
183265 </ div >
184266
185267 { /* Email */ }
@@ -199,6 +281,9 @@ const SignUpForm = ({ toggleSignUp }: Props) => {
199281 className = "py-3 px-4 block w-full border rounded-lg text-sm dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
200282 placeholder = "your@email.com"
201283 />
284+ { formErrors . email && (
285+ < p className = "text-xs text-red-600 mt-2" > { formErrors . email . message } </ p >
286+ ) }
202287 </ div >
203288
204289 { /* Password */ }
@@ -214,10 +299,26 @@ const SignUpForm = ({ toggleSignUp }: Props) => {
214299 value : 6 ,
215300 message : "Password must have at least 6 characters" ,
216301 } ,
302+ validate : ( value ) => {
303+ const hasUpperCase = / [ A - Z ] / . test ( value ) ;
304+ const hasLowerCase = / [ a - z ] / . test ( value ) ;
305+ const hasNumber = / [ 0 - 9 ] / . test ( value ) ;
306+ const hasSpecialChar = / [ ^ A - Z a - z 0 - 9 ] / . test ( value ) ;
307+
308+ if ( ! hasUpperCase ) return "Must include at least one uppercase letter" ;
309+ if ( ! hasLowerCase ) return "Must include at least one lowercase letter" ;
310+ if ( ! hasNumber ) return "Must include at least one number" ;
311+ if ( ! hasSpecialChar ) return "Must include at least one special character" ;
312+
313+ return true ;
314+ } ,
217315 } ) }
218316 className = "py-3 px-4 block w-full border rounded-lg text-sm dark:bg-slate-900 dark:border-gray-700 dark:text-gray-400"
219317 placeholder = "Enter a secure password"
220318 />
319+ { formErrors . password && (
320+ < p className = "text-xs text-red-600 mt-2" > { formErrors . password . message } </ p >
321+ ) }
221322 </ div >
222323
223324 < div >
@@ -252,31 +353,138 @@ const SignUpForm = ({ toggleSignUp }: Props) => {
252353 </ div >
253354
254355 { signing && (
255- < div className = "fixed inset-0 z-50 bg-black/50 backdrop-blur-sm flex items-center justify-center" >
256- < div className = "text-center" >
257- < div className = "flex justify-center gap-6 mb-6" >
258- { [ "#38bdf8" , "#7c3aed" , "#60a5fa" ] . map ( ( color , i ) => (
356+ < div className = "fixed inset-0 z-50 bg-black/70 backdrop-blur-sm flex items-center justify-center" >
357+ < div className = "bg-gray-800 rounded-xl p-8 max-w-md w-full shadow-2xl" >
358+ { /* Step progress with animation */ }
359+ < div className = "flex justify-center mb-8" >
360+ < div className = "relative w-24 h-24" >
361+ { /* Background circle */ }
362+ < div className = "absolute inset-0 rounded-full border-4 border-gray-700" > </ div >
363+
364+ { /* Progress circle with gradient */ }
365+ < svg className = "absolute inset-0 w-24 h-24 -rotate-90" >
366+ < circle
367+ className = "text-transparent"
368+ strokeWidth = "4"
369+ stroke = "currentColor"
370+ fill = "transparent"
371+ r = "38"
372+ cx = "48"
373+ cy = "48"
374+ />
375+ < circle
376+ className = "text-indigo-500 transition-all duration-300 ease-in-out"
377+ strokeWidth = "4"
378+ strokeLinecap = "round"
379+ stroke = "url(#gradient)"
380+ fill = "transparent"
381+ r = "38"
382+ cx = "48"
383+ cy = "48"
384+ strokeDasharray = { `${ 2 * Math . PI * 38 } ` }
385+ strokeDashoffset = { `${ 2 * Math . PI * 38 * ( 1 - progress / 100 ) } ` }
386+ />
387+
388+ { /* Define gradient */ }
389+ < defs >
390+ < linearGradient id = "gradient" x1 = "0%" y1 = "0%" x2 = "100%" y2 = "0%" >
391+ < stop offset = "0%" stopColor = "#8B5CF6" />
392+ < stop offset = "100%" stopColor = "#3B82F6" />
393+ </ linearGradient >
394+ </ defs >
395+ </ svg >
396+
397+ { /* Percentage text */ }
398+ < div className = "absolute inset-0 flex items-center justify-center" >
399+ < span className = "text-xl font-bold text-white" > { Math . round ( progress ) } %</ span >
400+ </ div >
401+ </ div >
402+ </ div >
403+
404+ { /* Stepper title */ }
405+ < h2 className = "text-xl font-bold text-center text-white mb-2" >
406+ { signupSteps [ currentStep ] ?. title || "Processing..." }
407+ </ h2 >
408+
409+ { /* Description */ }
410+ < p className = "text-gray-300 text-center mb-6" >
411+ { signupSteps [ currentStep ] ?. description || "Please wait..." }
412+ </ p >
413+
414+ { /* Stepper indicators */ }
415+ < div className = "flex justify-between items-center mb-4 px-2" >
416+ { signupSteps . map ( ( step , index ) => (
417+ < div key = { index } className = "flex flex-col items-center" >
418+ { /* Step connector line */ }
419+ { index > 0 && (
420+ < div
421+ className = { `h-0.5 w-full absolute -ml-full ${
422+ index <= currentStep ? "bg-gradient-to-r from-purple-500 to-blue-500" : "bg-gray-700"
423+ } `}
424+ style = { { width : "100%" , marginLeft : "-50%" , marginTop : "10px" , zIndex : 0 } }
425+ > </ div >
426+ ) }
427+
428+ { /* Step bubble */ }
429+ < div
430+ className = { `z-10 flex items-center justify-center w-7 h-7 rounded-full transition-all duration-500 ${
431+ index < currentStep
432+ ? "bg-gradient-to-r from-purple-500 to-blue-500"
433+ : index === currentStep
434+ ? "bg-gradient-to-r from-purple-400 to-blue-400 border-2 border-white animate-pulse"
435+ : "bg-gray-700"
436+ } `}
437+ >
438+ { index < currentStep ? (
439+ // Completed step check mark
440+ < svg className = "w-4 h-4 text-white" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
441+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = "2" d = "M5 13l4 4L19 7" > </ path >
442+ </ svg >
443+ ) : (
444+ // Step number
445+ < span className = "text-xs text-white font-medium" > { index + 1 } </ span >
446+ ) }
447+ </ div >
448+
449+ { /* Step label (visible on wider screens) */ }
450+ < div className = "hidden sm:block text-xs mt-2 text-center whitespace-nowrap" >
451+ < span
452+ className = { `${
453+ index <= currentStep ? "text-gray-200" : "text-gray-500"
454+ } font-medium`}
455+ >
456+ { step . title . split ( ' ' ) [ 0 ] }
457+ </ span >
458+ </ div >
459+ </ div >
460+ ) ) }
461+ </ div >
462+
463+ { /* Detailed status message */ }
464+ < div className = "text-center text-gray-400 text-sm mt-6 italic" >
465+ { stepMessage }
466+ </ div >
467+
468+ { /* Animated gear icons */ }
469+ < div className = "flex justify-center gap-4 mt-8 opacity-70" >
470+ { [ 24 , 20 , 16 ] . map ( ( size , i ) => (
259471 < svg
260472 key = { i }
261- className = { `w-16 h-16 ${
262- i === 1 ? "animate-spin-slow-reverse " : "animate-spin-slow"
473+ className = { `w-${ size } h-${ size } ${
474+ i % 2 === 0 ? "animate-spin-slow" : "animate-spin-slow-reverse "
263475 } `}
476+ style = { {
477+ animationDuration : `${ ( i + 3 ) * 2 } s` ,
478+ opacity : 0.6 + ( i * 0.1 )
479+ } }
264480 xmlns = "http://www.w3.org/2000/svg"
265- fill = { color }
481+ fill = { i === 0 ? "#8B5CF6" : i === 1 ? "#3B82F6" : "#EC4899" }
266482 viewBox = "0 0 24 24"
267483 >
268484 < path d = "M19.14 12.936a7.996 7.996 0 0 0 .047-.936 7.996 7.996 0 0 0-.047-.936l2.036-1.593a.5.5 0 0 0 .121-.63l-1.926-3.33a.5.5 0 0 0-.607-.218l-2.396.96a7.98 7.98 0 0 0-1.617-.936l-.36-2.52A.5.5 0 0 0 13.405 2h-2.81a.5.5 0 0 0-.492.415l-.36 2.52a7.98 7.98 0 0 0-1.617.936l-2.396-.96a.5.5 0 0 0-.607.218L2.197 8.46a.5.5 0 0 0 .121.63l2.036 1.593a7.996 7.996 0 0 0 0 1.872L2.318 14.15a.5.5 0 0 0-.121.63l1.926 3.33a.5.5 0 0 0 .607.218l2.396-.96a7.98 7.98 0 0 0 1.617.936l.36 2.52a.5.5 0 0 0 .492.415h2.81a.5.5 0 0 0 .492-.415l.36-2.52a7.98 7.98 0 0 0 1.617-.936l2.396.96a.5.5 0 0 0 .607-.218l1.926-3.33a.5.5 0 0 0-.121-.63l-2.036-1.593zM12 15.5a3.5 3.5 0 1 1 0-7 3.5 3.5 0 0 1 0 7z" />
269485 </ svg >
270486 ) ) }
271487 </ div >
272- < div className = "text-lg text-slate-300 mb-2" > { stepMessage } </ div >
273- < div className = "w-60 h-2 bg-slate-700 rounded-full overflow-hidden mx-auto" >
274- < div
275- className = "h-full bg-gradient-to-r from-blue-400 to-purple-600 transition-all duration-500"
276- style = { { width : `${ progress } %` } }
277- />
278- </ div >
279- < p className = "mt-2 text-xs text-slate-400" > { progress } % Complete</ p >
280488 </ div >
281489 </ div >
282490 ) }
@@ -289,6 +497,8 @@ export default SignUpForm;
289497
290498
291499
500+
501+
292502// second code comment
293503
294504// import { ENDPOINTS, fetcher } from "@api/useAxiosSWR";
0 commit comments