1- "use client" ;
2-
3- import { motion } from "framer-motion" ;
4-
5- import { useState } from "react" ;
6- import { useRouter } from "next/navigation" ;
7-
8- import { Button } from "@/components/ui/button" ;
9- import { Input } from "@/components/ui/input" ;
10- import { Label } from "@/components/ui/label" ;
11- import { Card } from "@/components/ui/card" ;
12-
13- import { ToastProvider } from "@/components/ui/toast" ;
14- import { useToast } from "@/hooks/use-toast" ;
15-
161import { Navbar } from "@/components/ui/navbar" ;
172
18- import { signUp , logIn } from "@/lib/models/auth" ; // Verify Email
19-
20- // +-------------------------------------------------------------------------------+
21- // | Step 1 UI Comp |
22- // +-------------------------------------------------------------------------------+
23-
24- export function Step1 ( { username, updateFormData, handleNext } : any ) {
25- const handleUsernameChange = ( e : React . ChangeEvent < HTMLInputElement > ) =>
26- updateFormData ( 'username' , e . target . value ) ;
27-
28- return (
29- < motion . div
30- className = "w-full max-w-md text-center"
31- initial = { { opacity : 0 } }
32- animate = { { opacity : 1 } }
33- exit = { { opacity : 0 } }
34- transition = { { duration : 0.5 } }
35- >
36- < Card className = "p-8 shadow-xl border rounded-xl bg-white/20 backdrop-blur-lg flex flex-col items-center justify-center space-y-4" >
37- < h1 className = "text-2xl text-white font-semibold mb-4" > Choose Your Username</ h1 >
38- < Input
39- value = { username }
40- onChange = { handleUsernameChange }
41- placeholder = "Enter a username"
42- required
43- className = "w-full text-black p-4 rounded-md border border-gray-300 shadow-sm"
44- />
45- < Button onClick = { handleNext } className = "mt-4 w-full bg-orange-500 hover:bg-black text-white py-2 rounded-3xl font-semibold" >
46- Next
47- </ Button >
48- </ Card >
49- </ motion . div >
50- ) ;
51- }
52-
53- // +-------------------------------------------------------------------------------+
54- // | Step 2 UI Comp |
55- // +-------------------------------------------------------------------------------+
56-
57- export function Step2 ( {
58- email,
59- password,
60- confirmPassword,
61- acceptedTerms,
62- updateFormData,
63- handleNext,
64- } : any ) {
65- return (
66- < motion . div
67- className = "w-full max-w-md text-center"
68- initial = { { opacity : 0 } }
69- animate = { { opacity : 1 } }
70- exit = { { opacity : 0 } }
71- transition = { { duration : 0.5 } }
72- >
73- < h1 className = "text-2xl mb-4" > Email and Password</ h1 >
74- < Input
75- value = { email }
76- onChange = { ( e ) => updateFormData ( 'email' , e . target . value ) }
77- placeholder = "Email"
78- required
79- />
80- < Input
81- value = { password }
82- onChange = { ( e ) => updateFormData ( 'password' , e . target . value ) }
83- placeholder = "Password"
84- type = "password"
85- required
86- />
87- < Input
88- value = { confirmPassword }
89- onChange = { ( e ) => updateFormData ( 'confirmPassword' , e . target . value ) }
90- placeholder = "Confirm Password"
91- type = "password"
92- required
93- />
94- < div className = "mt-2" >
95- < label className = "flex items-center" >
96- < input
97- type = "checkbox"
98- checked = { acceptedTerms }
99- onChange = { ( e ) => updateFormData ( 'acceptedTerms' , e . target . checked ) }
100- />
101- < span className = "ml-2" > I accept the terms and conditions</ span >
102- </ label >
103- </ div >
104- < Button onClick = { handleNext } className = "mt-4 w-full" >
105- Next
106- </ Button >
107- </ motion . div >
108- ) ;
109- }
110-
111- // +-------------------------------------------------------------------------------+
112- // | Step 3 UI Comp |
113- // +-------------------------------------------------------------------------------+
114-
115- export function Step3 ( { handleNext } : any ) {
116- return (
117- < motion . div
118- className = "w-full max-w-md text-center"
119- initial = { { opacity : 0 } }
120- animate = { { opacity : 1 } }
121- exit = { { opacity : 0 } }
122- transition = { { duration : 0.5 } }
123- >
124- < h1 className = "text-2xl mb-4" > Verify Your Email</ h1 >
125- < p > We've sent a verification link to your email. Please verify it before continuing.</ p >
126- < Button onClick = { handleNext } className = "mt-4 w-full" >
127- I've Verified
128- </ Button >
129- </ motion . div >
130- ) ;
131- }
132-
133- // +-------------------------------------------------------------------------------+
134- // | Step 4 UI Comp |
135- // +-------------------------------------------------------------------------------+
136-
137- export function Step4 ( { twoFactorEnabled, updateFormData, handleNext } : any ) {
138- return (
139- < motion . div
140- className = "w-full max-w-md text-center"
141- initial = { { opacity : 0 } }
142- animate = { { opacity : 1 } }
143- exit = { { opacity : 0 } }
144- transition = { { duration : 0.5 } }
145- >
146- < h1 className = "text-2xl mb-4" > Add Two-Factor Authentication</ h1 >
147- < p className = "mb-4" > Enhance your account security by enabling 2FA. This is optional.</ p >
148- < label className = "flex items-center justify-center" >
149- < input
150- type = "checkbox"
151- checked = { twoFactorEnabled }
152- onChange = { ( e ) => updateFormData ( 'twoFactorEnabled' , e . target . checked ) }
153- />
154- < span className = "ml-2" > Enable 2FA</ span >
155- </ label >
156- < Button onClick = { handleNext } className = "mt-4 w-full" >
157- Next
158- </ Button >
159- </ motion . div >
160- ) ;
161- }
162-
163- export function Step5 ( { avatar, updateFormData, handleFinish } : any ) {
164- const handleAvatarChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
165- const file = e . target . files ?. [ 0 ] || null ;
166- updateFormData ( 'avatar' , file ) ;
167- } ;
168-
169- return (
170- < motion . div
171- className = "w-full max-w-md text-center"
172- initial = { { opacity : 0 } }
173- animate = { { opacity : 1 } }
174- exit = { { opacity : 0 } }
175- transition = { { duration : 0.5 } }
176- >
177- < h1 className = "text-2xl mb-4" > Upload Your Avatar</ h1 >
178- < Input type = "file" accept = "image/*" onChange = { handleAvatarChange } />
179- { avatar && < p className = "mt-2" > File uploaded: { avatar . name } </ p > }
180- < Button onClick = { handleFinish } className = "mt-4 w-full" >
181- Finish
182- </ Button >
183- </ motion . div >
184- ) ;
185- }
186-
187- // +-------------------------------------------------------------------------------+
188- // | OnboardingFlow |
189- // +-------------------------------------------------------------------------------+
190-
191- export default function OnboardingFlow ( ) {
192- const [ step , setStep ] = useState ( 1 ) ;
193- const [ formData , setFormData ] = useState ( {
194- username : "" ,
195- email : "" ,
196- password : "" ,
197- confirmPassword : "" ,
198- acceptedTerms : false ,
199- twoFactorEnabled : false ,
200- avatar : null as File | null ,
201- } ) ;
202-
203- const router = useRouter ( ) ;
204- const { toast } = useToast ( ) ;
205-
206- const updateFormData = ( field : string , value : any ) => {
207- setFormData ( ( prev ) => ( { ...prev , [ field ] : value } ) ) ;
208- } ;
209-
210- const handleNext = async ( ) => {
211- if ( step === 2 && ! formData . acceptedTerms ) {
212- toast ( {
213- title : 'EULA Not Accepted' ,
214- description : 'You must accept the terms and conditions to proceed.' ,
215- variant : 'destructive' ,
216- } ) ;
217- return ;
218- }
219-
220- if ( step === 3 ) {
221- try {
222- //await verifyEmail(formData.email);
223- toast ( { title : 'Verification Email Sent' , description : 'Check your inbox.' } ) ;
224- } catch ( error ) {
225- toast ( {
226- title : 'Error Sending Verification' ,
227- description : ( error as Error ) ?. message || 'Please try again.' ,
228- variant : 'destructive' ,
229- } ) ;
230- return ;
231- }
232- }
233-
234- setStep ( ( prev ) => prev + 1 ) ;
235- } ;
236-
237- const handleFinish = async ( ) => {
238- try {
239- const { email, password, username, avatar } = formData ;
240- const userCredential = await signUp ( email , password ) ;
241-
242- if ( avatar ) { }
243-
244- router . push ( '/' ) ;
245- } catch ( error ) {
246- toast ( {
247- title : 'Signup Error' ,
248- description : ( error as Error ) ?. message || 'Please try again.' ,
249- variant : 'destructive' ,
250- } ) ;
251- }
252- } ;
253-
254- const renderStep = ( ) => {
255- switch ( step ) {
256- case 1 : return (
257- < Step1
258- username = { formData . username }
259- updateFormData = { updateFormData }
260- handleNext = { handleNext }
261- />
262- ) ;
263- case 2 : return (
264- < Step2
265- email = { formData . email }
266- password = { formData . password }
267- confirmPassword = { formData . confirmPassword }
268- acceptedTerms = { formData . acceptedTerms }
269- updateFormData = { updateFormData }
270- handleNext = { handleNext }
271- />
272- ) ;
273- case 3 : return < Step3 handleNext = { handleNext } /> ;
274- case 4 : return (
275- < Step4
276- twoFactorEnabled = { formData . twoFactorEnabled }
277- updateFormData = { updateFormData }
278- handleNext = { handleNext }
279- />
280- ) ;
281- case 5 : return (
282- < Step5
283- avatar = { formData . avatar }
284- updateFormData = { updateFormData }
285- handleFinish = { handleFinish }
286- />
287- ) ;
288- default : return < p > Something went wrong!</ p > ;
289- }
290- } ;
291-
292- return (
293- < ToastProvider >
294- < div className = "absolute inset-0 -z-10 bg-gradient-to-r from-purple-500 via-pink-500 to-orange-500 blur-3xl opacity-20" > </ div >
295- < Navbar />
296- < div className = "min-h-screen flex items-center justify-center p-4" >
297- { renderStep ( ) }
298- </ div >
299- </ ToastProvider >
300- ) ;
3+ export default function Auth ( ) {
4+
3015}
0 commit comments