Skip to content

Commit 0165c57

Browse files
committed
refactor(auth): remove password from login form for magic link flow
1 parent e5044f1 commit 0165c57

1 file changed

Lines changed: 45 additions & 80 deletions

File tree

app/login/page.tsx

Lines changed: 45 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,26 @@ import { Input } from "@/components/ui/input"
88
import { Label } from "@/components/ui/label"
99
import Link from "next/link"
1010
import { motion, AnimatePresence } from "framer-motion"
11-
import { signIn, checkRememberMe } from "@/lib/features/auth"
11+
import { signInWithEmail, checkRememberMe } from "@/lib/features/auth"
1212
import { getTranslations, getUserLanguage } from "@/lib/config"
1313
import { LanguageSwitcher } from "@/components/language-switcher"
14-
import {
15-
EyeIcon,
16-
EyeSlashIcon,
17-
LockClosedIcon,
18-
EnvelopeIcon,
19-
ArrowRightIcon,
20-
SparklesIcon,
21-
BoltIcon,
14+
import {
15+
EyeIcon,
16+
EyeSlashIcon,
17+
LockClosedIcon,
18+
EnvelopeIcon,
19+
ArrowRightIcon,
20+
SparklesIcon,
21+
BoltIcon,
2222
ShieldCheckIcon,
2323
CheckCircleIcon
2424
} from "@heroicons/react/24/outline"
2525

2626
export default function LoginPage() {
2727
const router = useRouter()
2828
const [email, setEmail] = useState("")
29-
const [password, setPassword] = useState("")
30-
const [rememberMe, setRememberMe] = useState(false)
3129
const [error, setError] = useState("")
32-
const [showPassword, setShowPassword] = useState(false)
30+
const [message, setMessage] = useState("")
3331
const [t, setT] = useState(getTranslations("en"))
3432

3533
useEffect(() => {
@@ -41,23 +39,24 @@ export default function LoginPage() {
4139
router.push("/dashboard")
4240
}
4341
}
44-
42+
4543
checkAuth()
4644
}, [router])
4745

4846
const handleLogin = async (e: React.FormEvent) => {
4947
e.preventDefault()
5048
setError("")
49+
setMessage("")
5150

52-
if (!email || !password) {
53-
setError("Email and password are required")
51+
if (!email) {
52+
setError(t.auth.email + " is required")
5453
return
5554
}
5655

57-
const result = await signIn(email, password, rememberMe)
56+
const result = await signInWithEmail(email)
5857

5958
if (result.success) {
60-
router.push("/dashboard")
59+
setMessage("Check your email for the magic link to sign in!")
6160
} else {
6261
setError(result.error || "Login failed")
6362
}
@@ -73,12 +72,12 @@ export default function LoginPage() {
7372
<div className="absolute bottom-[-10%] right-[-10%] w-[70%] h-[70%] bg-purple-600/20 rounded-full blur-[120px] animate-pulse delay-700"></div>
7473
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[50%] h-[50%] bg-pink-600/10 rounded-full blur-[120px] animate-pulse delay-1000"></div>
7574
</div>
76-
75+
7776
{/* Static noise texture */}
7877
<div className="absolute inset-0 opacity-20 pointer-events-none mix-blend-overlay bg-[url('https://grainy-gradients.vercel.app/noise.svg')]"></div>
7978

8079
<div className="relative z-10 flex flex-col justify-center items-center text-white p-20 w-full">
81-
<motion.div
80+
<motion.div
8281
initial={{ opacity: 0, x: -50 }}
8382
animate={{ opacity: 1, x: 0 }}
8483
transition={{ duration: 0.8, ease: "easeOut" }}
@@ -95,7 +94,7 @@ export default function LoginPage() {
9594
<p className="text-xs font-bold uppercase tracking-[0.4em] text-primary/80">Innovation Lab</p>
9695
</div>
9796
</div>
98-
97+
9998
<div className="space-y-6">
10099
<h2 className="text-5xl font-bold leading-tight tracking-tight text-balance">
101100
Build something <br />
@@ -112,11 +111,11 @@ export default function LoginPage() {
112111
{ icon: CheckCircleIcon, title: "Collaboration", desc: "Work with your team in real-time" },
113112
{ icon: ShieldCheckIcon, title: "Secure & Private", desc: "Your data is always protected" }
114113
].map((item, idx) => (
115-
<motion.div
114+
<motion.div
116115
initial={{ opacity: 0, y: 10 }}
117116
animate={{ opacity: 1, y: 0 }}
118117
transition={{ delay: 0.5 + idx * 0.1 }}
119-
key={idx}
118+
key={idx}
120119
className="flex items-start gap-5 p-4 rounded-2xl hover:bg-white/5 transition-colors border border-transparent hover:border-white/5 group"
121120
>
122121
<div className="rounded-xl bg-primary/10 border border-primary/20 p-3 mt-1 group-hover:bg-primary/20 transition-all">
@@ -137,12 +136,12 @@ export default function LoginPage() {
137136
<div className="flex-1 flex items-center justify-center p-8 bg-slate-950 relative overflow-hidden">
138137
{/* Background glow for mobile */}
139138
<div className="lg:hidden absolute top-[-20%] left-[-20%] w-full h-full bg-primary/5 rounded-full blur-[100px] pointer-events-none"></div>
140-
139+
141140
<div className="absolute top-8 right-8 z-20">
142141
<LanguageSwitcher />
143142
</div>
144143

145-
<motion.div
144+
<motion.div
146145
initial={{ opacity: 0, y: 20 }}
147146
animate={{ opacity: 1, y: 0 }}
148147
transition={{ duration: 0.8 }}
@@ -166,7 +165,7 @@ export default function LoginPage() {
166165
<form onSubmit={handleLogin} className="space-y-6">
167166
<AnimatePresence>
168167
{error && (
169-
<motion.div
168+
<motion.div
170169
initial={{ opacity: 0, height: 0 }}
171170
animate={{ opacity: 1, height: "auto" }}
172171
exit={{ opacity: 0, height: 0 }}
@@ -178,6 +177,19 @@ export default function LoginPage() {
178177
</div>
179178
</motion.div>
180179
)}
180+
{message && (
181+
<motion.div
182+
initial={{ opacity: 0, height: 0 }}
183+
animate={{ opacity: 1, height: "auto" }}
184+
exit={{ opacity: 0, height: 0 }}
185+
className="rounded-2xl border border-green-500/50 bg-green-500/5 p-4 text-sm text-green-400 overflow-hidden"
186+
>
187+
<div className="flex items-center gap-3">
188+
<div className="w-1.5 h-6 bg-green-500 rounded-full"></div>
189+
<p className="font-medium">{message}</p>
190+
</div>
191+
</motion.div>
192+
)}
181193
</AnimatePresence>
182194

183195
<div className="space-y-5">
@@ -200,77 +212,30 @@ export default function LoginPage() {
200212
/>
201213
</div>
202214
</div>
203-
204-
<div className="space-y-2">
205-
<Label htmlFor="password" className="text-xs font-bold uppercase tracking-widest text-slate-500 ml-1">
206-
{t.auth.password}
207-
</Label>
208-
<div className="relative group">
209-
<div className="absolute left-4 top-1/2 -translate-y-1/2 flex items-center justify-center">
210-
<LockClosedIcon className="h-5 w-5 text-slate-500 group-focus-within:text-primary transition-colors" />
211-
</div>
212-
<Input
213-
id="password"
214-
type={showPassword ? "text" : "password"}
215-
placeholder="••••••••"
216-
value={password}
217-
onChange={(e) => setPassword(e.target.value)}
218-
className="pl-12 pr-12 h-14 bg-white/[0.03] border-white/5 hover:border-white/10 focus:border-primary/50 transition-all rounded-2xl text-lg placeholder:text-slate-600 focus:ring-0 focus:bg-white/[0.05]"
219-
required
220-
/>
221-
<button
222-
type="button"
223-
onClick={() => setShowPassword(!showPassword)}
224-
className="absolute right-4 top-1/2 -translate-y-1/2 text-slate-500 hover:text-white transition-colors"
225-
>
226-
{showPassword ? <EyeSlashIcon className="h-5 w-5" /> : <EyeIcon className="h-5 w-5" />}
227-
</button>
228-
</div>
229-
</div>
230215
</div>
231216

232-
<div className="flex items-center justify-between px-1">
233-
<label className="flex items-center gap-3 cursor-pointer group">
234-
<div className="relative">
235-
<input
236-
type="checkbox"
237-
checked={rememberMe}
238-
onChange={(e) => setRememberMe(e.target.checked)}
239-
className="peer appearance-none w-5 h-5 rounded-md border border-white/10 checked:bg-primary checked:border-primary transition-all cursor-pointer"
240-
/>
241-
<CheckCircleIcon className="absolute top-0.5 left-0.5 w-4 h-4 text-slate-950 opacity-0 peer-checked:opacity-100 transition-opacity pointer-events-none" />
242-
</div>
243-
<span className="text-sm font-medium text-slate-400 group-hover:text-slate-300 transition-colors">
244-
{t.auth.rememberMe}
245-
</span>
246-
</label>
247-
<Link href="#" className="text-sm text-primary hover:text-white font-bold transition-colors">
248-
Forgot password?
249-
</Link>
250-
</div>
251-
252-
<Button
253-
type="submit"
217+
<Button
218+
type="submit"
254219
className="w-full h-14 text-lg font-black uppercase tracking-widest bg-primary hover:bg-primary/90 text-slate-950 shadow-[0_0_20px_rgba(var(--primary-rgb),0.3)] hover:shadow-[0_0_30px_rgba(var(--primary-rgb),0.5)] transition-all group rounded-2xl"
255220
>
256-
Sign In
221+
Send Magic Link
257222
<ArrowRightIcon className="ml-3 h-5 w-5 group-hover:translate-x-1.5 transition-transform" />
258223
</Button>
259224
</form>
260225

261226
<footer className="pt-6 space-y-6 text-center border-t border-white/5">
262227
<p className="text-slate-500 font-medium">
263228
Don't have an account?{" "}
264-
<Link
265-
href="/signup"
229+
<Link
230+
href="/signup"
266231
className="text-white hover:text-primary font-bold underline decoration-primary/30 underline-offset-4 decoration-2 transition-all"
267232
>
268233
Sign Up
269234
</Link>
270235
</p>
271-
272-
<Link
273-
href="/"
236+
237+
<Link
238+
href="/"
274239
className="inline-flex items-center gap-2 text-sm font-bold uppercase tracking-widest text-slate-600 hover:text-primary transition-all"
275240
>
276241
<span>← Back to Home</span>

0 commit comments

Comments
 (0)