diff --git a/apps/web/src/app/(auth)/forgot-password/page.tsx b/apps/web/src/app/(auth)/forgot-password/page.tsx new file mode 100644 index 0000000..84e5977 --- /dev/null +++ b/apps/web/src/app/(auth)/forgot-password/page.tsx @@ -0,0 +1,133 @@ +'use client'; + +import Link from 'next/link'; +import { useState } from 'react'; + +export default function ForgotPasswordPage() { + const [email, setEmail] = useState(''); + const [error, setError] = useState(''); + const [success, setSuccess] = useState(false); + const [loading, setLoading] = useState(false); + + async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + setError(''); + setLoading(true); + + try { + // Call the password reset API endpoint + const response = await fetch('/api/auth/forget-password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + email, + redirectTo: `${window.location.origin}/reset-password`, + }), + }); + + if (!response.ok) { + const data = await response.json(); + setError(data.message || 'Failed to send reset email'); + setLoading(false); + return; + } + + setSuccess(true); + setLoading(false); + } catch (err) { + console.error('Forgot password exception:', err); + setError('An unexpected error occurred'); + setLoading(false); + } + } + + if (success) { + return ( +
+
+

Check Your Email

+

+ If an account exists for {email}, we've sent a password reset + link. +

+
+ +
+ Check your inbox and click the link to reset your password. The link will expire in 1 + hour. +
+ +

+ Didn't receive the email?{' '} + +

+ +

+ + Back to Sign In + +

+
+ ); + } + + return ( +
+
+

Reset Password

+

+ Enter your email and we'll send you a reset link +

+
+ +
+ {error && ( +
+ {error} +
+ )} + +
+ + setEmail(e.target.value)} + required + className="w-full px-3 py-2 border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-foreground focus:border-transparent" + placeholder="you@example.com" + /> +
+ + +
+ +

+ Remember your password?{' '} + + Sign in + +

+
+ ); +} diff --git a/apps/web/src/app/(auth)/sign-in/page.tsx b/apps/web/src/app/(auth)/sign-in/page.tsx index 4ff83c9..d23dc99 100644 --- a/apps/web/src/app/(auth)/sign-in/page.tsx +++ b/apps/web/src/app/(auth)/sign-in/page.tsx @@ -4,9 +4,49 @@ import { signIn } from '@/lib/auth-client'; import Link from 'next/link'; import { useState } from 'react'; +function EyeIcon({ className }: { className?: string }) { + return ( + + + + + ); +} + +function EyeOffIcon({ className }: { className?: string }) { + return ( + + + + ); +} + export default function SignInPage() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); + const [showPassword, setShowPassword] = useState(false); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); @@ -88,18 +128,36 @@ export default function SignInPage() {
- - setPassword(e.target.value)} - required - className="w-full px-3 py-2 border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-foreground focus:border-transparent" - placeholder="Enter your password" - /> +
+ + + Forgot password? + +
+
+ setPassword(e.target.value)} + required + className="w-full px-3 py-2 pr-10 border border-border rounded-md bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-foreground focus:border-transparent" + placeholder="Enter your password" + /> + +