22
33import { useEffect , useState } from "react"
44import { useRouter } from "next/navigation"
5- import { Github , Loader2 , UserPlus } from "lucide-react"
5+ import { Github , Loader2 } from "lucide-react"
66import { Button } from "@/components/ui/button"
7- import { Input } from "@/components/ui/input"
8- import { Label } from "@/components/ui/label"
9- import { loginUser , registerUser , getLoginUrl } from "@/lib/api"
107import { useAuth } from "@/hooks/use-auth"
118import { openExternal } from "@/lib/utils"
12-
13- type Tab = "email" | "github"
9+ import { getLoginUrl } from "@/lib/api"
1410
1511export default function LoginPage ( ) {
1612 const router = useRouter ( )
17- const { refreshUser, isAuthenticated, isLoading : authLoading } = useAuth ( )
18- const [ activeTab , setActiveTab ] = useState < Tab > ( "email" )
19- const [ username , setUsername ] = useState ( "" )
20- const [ password , setPassword ] = useState ( "" )
13+ const { isAuthenticated, isLoading : authLoading } = useAuth ( )
2114 const [ error , setError ] = useState < string | null > ( null )
2215 const [ isLoading , setIsLoading ] = useState ( false )
23- const [ isRegistering , setIsRegistering ] = useState ( false )
2416
25- const handleLogin = async ( e : React . FormEvent ) => {
26- e . preventDefault ( )
27- setError ( null )
17+ const handleGitHubLogin = async ( ) => {
2818 setIsLoading ( true )
29-
30- try {
31- const data = await loginUser ( username , password )
32- localStorage . setItem ( "token" , data . token )
33- await refreshUser ( )
34- router . push ( "/" )
35- } catch ( err ) {
36- setError ( err instanceof Error ? err . message : "Login failed" )
37- } finally {
38- setIsLoading ( false )
39- }
40- }
41-
42- const handleRegister = async ( e : React . FormEvent ) => {
43- e . preventDefault ( )
4419 setError ( null )
45- setIsLoading ( true )
46-
47- try {
48- const data = await registerUser ( username , password )
49- localStorage . setItem ( "token" , data . token )
50- await refreshUser ( )
51- router . push ( "/" )
52- } catch ( err ) {
53- setError ( err instanceof Error ? err . message : "Registration failed" )
54- } finally {
55- setIsLoading ( false )
56- }
57- }
58-
59- const handleGitHubLogin = async ( ) => {
6020 try {
6121 await openExternal ( getLoginUrl ( ) )
6222 } catch {
@@ -77,7 +37,7 @@ export default function LoginPage() {
7737 < div className = "text-center mb-8" >
7838 < img
7939 src = "/logo.png"
80- alt = "OpenLinear"
40+ alt = "OpenLinear"
8141 className = "h-12 mx-auto mb-4"
8242 />
8343 < p className = "text-sm text-linear-text-secondary" >
@@ -86,127 +46,35 @@ export default function LoginPage() {
8646 </ div >
8747
8848 { /* Card */ }
89- < div className = "bg-linear-bg-secondary border border-linear-border rounded-lg overflow-hidden" >
90- { /* Tab Buttons */ }
91- < div className = "flex border-b border-linear-border" >
92- < button
93- type = "button"
94- onClick = { ( ) => setActiveTab ( "email" ) }
95- className = { `flex-1 px-4 py-3 text-sm font-medium transition-colors ${
96- activeTab === "email"
97- ? "text-linear-text border-b-2 border-linear-accent"
98- : "text-linear-text-secondary hover:text-linear-text"
99- } `}
100- >
101- Email / Password
102- </ button >
103- < button
104- type = "button"
105- onClick = { ( ) => setActiveTab ( "github" ) }
106- className = { `flex-1 px-4 py-3 text-sm font-medium transition-colors ${
107- activeTab === "github"
108- ? "text-linear-text border-b-2 border-linear-accent"
109- : "text-linear-text-secondary hover:text-linear-text"
110- } `}
111- >
112- GitHub
113- </ button >
114- </ div >
115-
116- { /* Content */ }
117- < div className = "p-6" >
118- { activeTab === "email" && (
119- < div className = "space-y-4" >
120- < form onSubmit = { isRegistering ? handleRegister : handleLogin } className = "space-y-4" >
121- < div className = "space-y-2" >
122- < Label htmlFor = "username" className = "text-linear-text" >
123- Username
124- </ Label >
125- < Input
126- id = "username"
127- type = "text"
128- placeholder = "Enter your username"
129- value = { username }
130- onChange = { ( e ) => setUsername ( e . target . value ) }
131- className = "bg-linear-bg border-linear-border text-linear-text placeholder:text-linear-text-tertiary focus:border-linear-accent"
132- required
133- />
134- </ div >
135-
136- < div className = "space-y-2" >
137- < Label htmlFor = "password" className = "text-linear-text" >
138- Password
139- </ Label >
140- < Input
141- id = "password"
142- type = "password"
143- placeholder = "Enter your password"
144- value = { password }
145- onChange = { ( e ) => setPassword ( e . target . value ) }
146- className = "bg-linear-bg border-linear-border text-linear-text placeholder:text-linear-text-tertiary focus:border-linear-accent"
147- required
148- />
149- </ div >
150-
151- { error && (
152- < div className = "p-3 rounded-md bg-destructive/10 border border-destructive/20" >
153- < p className = "text-sm text-destructive" > { error } </ p >
154- </ div >
155- ) }
156-
157- < div className = "flex gap-3 pt-2" >
158- < Button
159- type = "submit"
160- disabled = { isLoading }
161- className = "flex-1 bg-linear-accent hover:bg-linear-accent-hover text-white"
162- >
163- { isLoading ? (
164- < >
165- < Loader2 className = "w-4 h-4 mr-2 animate-spin" />
166- { isRegistering ? "Creating account..." : "Signing in..." }
167- </ >
168- ) : (
169- isRegistering ? "Create Account" : "Sign In"
170- ) }
171- </ Button >
172- < Button
173- type = "button"
174- variant = "outline"
175- onClick = { ( ) => {
176- setIsRegistering ( ! isRegistering )
177- setError ( null )
178- } }
179- className = "border-linear-border text-linear-text-secondary hover:text-linear-text hover:bg-linear-bg-tertiary"
180- >
181- < UserPlus className = "w-4 h-4 mr-2" />
182- { isRegistering ? "Back to Login" : "Register" }
183- </ Button >
184- </ div >
185- </ form >
49+ < div className = "bg-linear-bg-secondary border border-linear-border rounded-lg p-6" >
50+ < div className = "space-y-4" >
51+ < p className = "text-sm text-linear-text-secondary text-center" >
52+ Sign in with your GitHub account to access OpenLinear
53+ </ p >
54+
55+ { error && (
56+ < div className = "p-3 rounded-md bg-destructive/10 border border-destructive/20" >
57+ < p className = "text-sm text-destructive" > { error } </ p >
18658 </ div >
18759 ) }
18860
189- { activeTab === "github" && (
190- < div className = "space-y-4" >
191- < p className = "text-sm text-linear-text-secondary text-center" >
192- Sign in with your GitHub account to access OpenLinear
193- </ p >
194-
195- { error && (
196- < div className = "p-3 rounded-md bg-destructive/10 border border-destructive/20" >
197- < p className = "text-sm text-destructive" > { error } </ p >
198- </ div >
199- ) }
200-
201- < Button
202- onClick = { handleGitHubLogin }
203- className = "w-full bg-[#24292e] hover:bg-[#1b1f23] text-white"
204- >
61+ < Button
62+ onClick = { handleGitHubLogin }
63+ disabled = { isLoading }
64+ className = "w-full bg-[#24292e] hover:bg-[#1b1f23] text-white disabled:opacity-70"
65+ >
66+ { isLoading ? (
67+ < >
68+ < Loader2 className = "w-5 h-5 mr-2 animate-spin" />
69+ Waiting for GitHub...
70+ </ >
71+ ) : (
72+ < >
20573 < Github className = "w-5 h-5 mr-2" />
20674 Sign in with GitHub
207- </ Button >
208- </ div >
209- ) }
75+ </ >
76+ ) }
77+ </ Button >
21078 </ div >
21179 </ div >
21280
0 commit comments