11// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22
3- import { createFileRoute , Link , useNavigate } from '@tanstack/react-router' ;
4- import { useEffect , useState } from 'react' ;
5- import { useClient } from '@objectstack/client-react' ;
6- import { Button } from '@/components/ui/button' ;
7- import { Card , CardContent , CardDescription , CardFooter , CardHeader , CardTitle } from '@/components/ui/card' ;
8- import { Input } from '@/components/ui/input' ;
9- import { Label } from '@/components/ui/label' ;
10- import { toast } from '@/hooks/use-toast' ;
11- import { useSession } from '@/hooks/useSession' ;
12- import { SocialSignInButtons } from '@/components/auth/social-sign-in-buttons' ;
3+ import { createFileRoute , Link , useNavigate } from "@tanstack/react-router" ;
4+ import { useEffect , useState } from "react" ;
5+ import { useClient } from "@objectstack/client-react" ;
6+ import { Button } from "@/components/ui/button" ;
7+ import { Card , CardContent , CardDescription , CardHeader , CardTitle } from "@/components/ui/card" ;
8+ import { Input } from "@/components/ui/input" ;
9+ import { Label } from "@/components/ui/label" ;
10+ import { toast } from "@/hooks/use-toast" ;
11+ import { useSession } from "@/hooks/useSession" ;
12+ import { SocialSignInButtons } from "@/components/auth/social-sign-in-buttons" ;
13+ import { GalleryVerticalEnd } from "lucide-react" ;
1314
14- export const Route = createFileRoute ( ' /register' ) ( {
15+ export const Route = createFileRoute ( " /register" ) ( {
1516 component : RegisterPage ,
1617} ) ;
1718
1819function RegisterPage ( ) {
1920 const navigate = useNavigate ( ) ;
2021 const client = useClient ( ) as any ;
2122 const { user, refresh } = useSession ( ) ;
22- const [ name , setName ] = useState ( '' ) ;
23- const [ email , setEmail ] = useState ( '' ) ;
24- const [ password , setPassword ] = useState ( '' ) ;
23+ const [ name , setName ] = useState ( "" ) ;
24+ const [ email , setEmail ] = useState ( "" ) ;
25+ const [ password , setPassword ] = useState ( "" ) ;
2526 const [ submitting , setSubmitting ] = useState ( false ) ;
2627
2728 useEffect ( ( ) => {
2829 if ( user ) {
29- navigate ( { to : '/' } ) ;
30+ navigate ( { to : "/" } ) ;
3031 }
3132 } , [ user , navigate ] ) ;
3233
@@ -37,76 +38,91 @@ function RegisterPage() {
3738 try {
3839 await client . auth . register ( { name, email, password } ) ;
3940 await refresh ( ) ;
40- toast ( { title : ' Account created' } ) ;
41- navigate ( { to : ' /orgs/new' } ) ;
41+ toast ( { title : " Account created" } ) ;
42+ navigate ( { to : " /orgs/new" } ) ;
4243 } catch ( err ) {
4344 toast ( {
44- title : ' Sign up failed' ,
45+ title : " Sign up failed" ,
4546 description : ( err as Error ) . message ,
46- variant : ' destructive' ,
47+ variant : " destructive" ,
4748 } ) ;
4849 } finally {
4950 setSubmitting ( false ) ;
5051 }
5152 } ;
5253
5354 return (
54- < div className = "flex flex-1 items-center justify-center bg-background px-4" >
55- < Card className = "w-full max-w-sm" >
56- < CardHeader >
57- < CardTitle > Create account</ CardTitle >
58- < CardDescription > Join ObjectStack Studio.</ CardDescription >
59- </ CardHeader >
60- < form onSubmit = { handleSubmit } >
61- < CardContent className = "space-y-4" >
62- < SocialSignInButtons mode = "sign-up" />
63- < div className = "space-y-1.5" >
64- < Label htmlFor = "name" > Name</ Label >
65- < Input
66- id = "name"
67- autoComplete = "name"
68- required
69- value = { name }
70- onChange = { ( e ) => setName ( e . target . value ) }
71- />
72- </ div >
73- < div className = "space-y-1.5" >
74- < Label htmlFor = "email" > Email</ Label >
75- < Input
76- id = "email"
77- type = "email"
78- autoComplete = "email"
79- required
80- value = { email }
81- onChange = { ( e ) => setEmail ( e . target . value ) }
82- />
83- </ div >
84- < div className = "space-y-1.5" >
85- < Label htmlFor = "password" > Password</ Label >
86- < Input
87- id = "password"
88- type = "password"
89- autoComplete = "new-password"
90- required
91- minLength = { 8 }
92- value = { password }
93- onChange = { ( e ) => setPassword ( e . target . value ) }
94- />
95- </ div >
96- </ CardContent >
97- < CardFooter className = "flex flex-col gap-3" >
98- < Button type = "submit" className = "w-full" disabled = { submitting } >
99- { submitting ? 'Creating…' : 'Create account' }
100- </ Button >
101- < p className = "text-xs text-muted-foreground" >
102- Already have an account?{ ' ' }
103- < Link to = "/login" className = "text-primary hover:underline" >
104- Sign in
105- </ Link >
106- </ p >
107- </ CardFooter >
108- </ form >
109- </ Card >
55+ < div className = "flex min-h-svh w-full flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10" >
56+ < div className = "flex w-full max-w-sm flex-col gap-6" >
57+ < a href = "#" className = "flex items-center gap-2 self-center font-medium" >
58+ < div className = "flex size-6 items-center justify-center rounded-md bg-primary text-primary-foreground" >
59+ < GalleryVerticalEnd className = "size-4" />
60+ </ div >
61+ ObjectStack
62+ </ a >
63+ < div className = "flex flex-col gap-6" >
64+ < Card >
65+ < CardHeader className = "text-center" >
66+ < CardTitle className = "text-xl" > Create an account</ CardTitle >
67+ < CardDescription > Join ObjectStack Studio.</ CardDescription >
68+ </ CardHeader >
69+ < CardContent >
70+ < form onSubmit = { handleSubmit } >
71+ < div className = "flex flex-col gap-4" >
72+ < SocialSignInButtons mode = "sign-up" />
73+ < div className = "flex flex-col gap-2" >
74+ < Label htmlFor = "name" > Name</ Label >
75+ < Input
76+ id = "name"
77+ autoComplete = "name"
78+ required
79+ value = { name }
80+ onChange = { ( e ) => setName ( e . target . value ) }
81+ />
82+ </ div >
83+ < div className = "flex flex-col gap-2" >
84+ < Label htmlFor = "email" > Email</ Label >
85+ < Input
86+ id = "email"
87+ type = "email"
88+ placeholder = "m@example.com"
89+ autoComplete = "email"
90+ required
91+ value = { email }
92+ onChange = { ( e ) => setEmail ( e . target . value ) }
93+ />
94+ </ div >
95+ < div className = "flex flex-col gap-2" >
96+ < Label htmlFor = "password" > Password</ Label >
97+ < Input
98+ id = "password"
99+ type = "password"
100+ autoComplete = "new-password"
101+ required
102+ minLength = { 8 }
103+ value = { password }
104+ onChange = { ( e ) => setPassword ( e . target . value ) }
105+ />
106+ </ div >
107+ < Button type = "submit" className = "w-full" disabled = { submitting } >
108+ { submitting ? "Creating…" : "Create account" }
109+ </ Button >
110+ < p className = "text-center text-sm text-muted-foreground" >
111+ Already have an account?{ " " }
112+ < Link to = "/login" className = "underline underline-offset-4 hover:text-primary" >
113+ Sign in
114+ </ Link >
115+ </ p >
116+ </ div >
117+ </ form >
118+ </ CardContent >
119+ </ Card >
120+ < p className = "px-6 text-center text-xs text-muted-foreground [&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-primary" >
121+ By clicking continue, you agree to our{ " " }
122+ < a href = "#" > Terms of Service</ a > and < a href = "#" > Privacy Policy</ a > .
123+ </ p >
124+ </ div >
125+ </ div >
110126 </ div >
111127 ) ;
112128}
0 commit comments