lmao
This commit is contained in:
parent
03445188ea
commit
524580eb25
102 changed files with 36625 additions and 1295 deletions
|
|
@ -1,5 +1,7 @@
|
|||
import { useState, useCallback } from 'react';
|
||||
import { CloseIcon } from './icons/CloseIcon';
|
||||
import { GoogleIcon } from './icons/GoogleIcon';
|
||||
import { AppleIcon } from './icons/AppleIcon';
|
||||
|
||||
type View = 'login' | 'register' | 'forgot';
|
||||
|
||||
|
|
@ -7,6 +9,7 @@ export default function AuthModal({
|
|||
onClose,
|
||||
onLogin,
|
||||
onRegister,
|
||||
onOAuthLogin,
|
||||
onForgotPassword,
|
||||
loading,
|
||||
error,
|
||||
|
|
@ -16,6 +19,7 @@ export default function AuthModal({
|
|||
onClose: () => void;
|
||||
onLogin: (email: string, password: string) => Promise<void>;
|
||||
onRegister: (email: string, password: string) => Promise<void>;
|
||||
onOAuthLogin: (provider: string) => Promise<void>;
|
||||
onForgotPassword: (email: string) => Promise<void>;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
|
|
@ -57,6 +61,18 @@ export default function AuthModal({
|
|||
[view, email, password, onLogin, onRegister, onForgotPassword, onClose]
|
||||
);
|
||||
|
||||
const handleOAuth = useCallback(
|
||||
async (provider: string) => {
|
||||
try {
|
||||
await onOAuthLogin(provider);
|
||||
onClose();
|
||||
} catch {
|
||||
// Error is handled by the hook
|
||||
}
|
||||
},
|
||||
[onOAuthLogin, onClose]
|
||||
);
|
||||
|
||||
const title =
|
||||
view === 'login' ? 'Log in' : view === 'register' ? 'Create account' : 'Reset password';
|
||||
|
||||
|
|
@ -104,82 +120,117 @@ export default function AuthModal({
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* Form */}
|
||||
<form onSubmit={handleSubmit} className="p-5 space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-warm-700 dark:text-warm-300 mb-1">
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
className="w-full px-3 py-2 text-sm rounded border border-warm-200 dark:border-warm-700 bg-white dark:bg-warm-800 text-navy-950 dark:text-white placeholder-warm-400 dark:placeholder-warm-500 outline-none focus:ring-2 ring-teal-400 dark:ring-teal-500"
|
||||
placeholder="you@example.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="p-5 space-y-4">
|
||||
{/* OAuth buttons (hidden in forgot view) */}
|
||||
{view !== 'forgot' && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-warm-700 dark:text-warm-300 mb-1">
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
minLength={8}
|
||||
className="w-full px-3 py-2 text-sm rounded border border-warm-200 dark:border-warm-700 bg-white dark:bg-warm-800 text-navy-950 dark:text-white placeholder-warm-400 dark:placeholder-warm-500 outline-none focus:ring-2 ring-teal-400 dark:ring-teal-500"
|
||||
placeholder={view === 'register' ? 'Min 8 characters' : 'Your password'}
|
||||
/>
|
||||
{view === 'login' && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => switchView('forgot')}
|
||||
className="mt-1 text-xs text-teal-600 dark:text-teal-400 hover:text-teal-800 dark:hover:text-teal-300"
|
||||
onClick={() => handleOAuth('google')}
|
||||
disabled={loading}
|
||||
className="w-full flex items-center justify-center gap-2 py-2 px-4 rounded border border-warm-200 dark:border-warm-700 bg-white dark:bg-warm-800 text-navy-950 dark:text-warm-100 text-sm font-medium hover:bg-warm-50 dark:hover:bg-warm-700 disabled:opacity-50 disabled:cursor-wait"
|
||||
>
|
||||
Forgot password?
|
||||
<GoogleIcon className="w-4 h-4" />
|
||||
Continue with Google
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleOAuth('apple')}
|
||||
disabled={loading}
|
||||
className="w-full flex items-center justify-center gap-2 py-2 px-4 rounded bg-navy-950 dark:bg-white text-white dark:text-navy-950 text-sm font-medium hover:bg-navy-900 dark:hover:bg-warm-100 disabled:opacity-50 disabled:cursor-wait"
|
||||
>
|
||||
<AppleIcon className="w-4 h-4" />
|
||||
Continue with Apple
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Divider */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex-1 h-px bg-warm-200 dark:bg-warm-700" />
|
||||
<span className="text-xs text-warm-400 dark:text-warm-500">or</span>
|
||||
<div className="flex-1 h-px bg-warm-200 dark:bg-warm-700" />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Email form */}
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-warm-700 dark:text-warm-300 mb-1">
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
className="w-full px-3 py-2 text-sm rounded border border-warm-200 dark:border-warm-700 bg-white dark:bg-warm-800 text-navy-950 dark:text-white placeholder-warm-400 dark:placeholder-warm-500 outline-none focus:ring-2 ring-teal-400 dark:ring-teal-500"
|
||||
placeholder="you@example.com"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{view === 'forgot' && resetSent && (
|
||||
<p className="text-sm text-teal-700 dark:text-teal-400">
|
||||
Check your email for a reset link.
|
||||
</p>
|
||||
)}
|
||||
{view !== 'forgot' && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-warm-700 dark:text-warm-300 mb-1">
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
minLength={8}
|
||||
className="w-full px-3 py-2 text-sm rounded border border-warm-200 dark:border-warm-700 bg-white dark:bg-warm-800 text-navy-950 dark:text-white placeholder-warm-400 dark:placeholder-warm-500 outline-none focus:ring-2 ring-teal-400 dark:ring-teal-500"
|
||||
placeholder={view === 'register' ? 'Min 8 characters' : 'Your password'}
|
||||
/>
|
||||
{view === 'login' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => switchView('forgot')}
|
||||
className="mt-1 text-xs text-teal-600 dark:text-teal-400 hover:text-teal-800 dark:hover:text-teal-300"
|
||||
>
|
||||
Forgot password?
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && <p className="text-sm text-red-600 dark:text-red-300">{error}</p>}
|
||||
{view === 'forgot' && resetSent && (
|
||||
<p className="text-sm text-teal-700 dark:text-teal-400">
|
||||
Check your email for a reset link.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{!(view === 'forgot' && resetSent) && (
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="w-full py-2 rounded bg-teal-600 text-white text-sm font-medium hover:bg-teal-700 dark:hover:bg-teal-600 disabled:opacity-50 disabled:cursor-wait transition-colors"
|
||||
>
|
||||
{loading
|
||||
? 'Please wait...'
|
||||
: view === 'login'
|
||||
? 'Log in'
|
||||
: view === 'register'
|
||||
? 'Create account'
|
||||
: 'Send reset link'}
|
||||
</button>
|
||||
)}
|
||||
{error && <p className="text-sm text-red-600 dark:text-red-300">{error}</p>}
|
||||
|
||||
{view === 'forgot' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => switchView('login')}
|
||||
className="w-full text-center text-sm text-teal-600 dark:text-teal-400 hover:text-teal-800 dark:hover:text-teal-300"
|
||||
>
|
||||
Back to login
|
||||
</button>
|
||||
)}
|
||||
</form>
|
||||
{!(view === 'forgot' && resetSent) && (
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="w-full py-2 rounded bg-teal-600 text-white text-sm font-medium hover:bg-teal-700 dark:hover:bg-teal-600 disabled:opacity-50 disabled:cursor-wait transition-colors"
|
||||
>
|
||||
{loading
|
||||
? 'Please wait...'
|
||||
: view === 'login'
|
||||
? 'Log in'
|
||||
: view === 'register'
|
||||
? 'Create account'
|
||||
: 'Send reset link'}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{view === 'forgot' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => switchView('login')}
|
||||
className="w-full text-center text-sm text-teal-600 dark:text-teal-400 hover:text-teal-800 dark:hover:text-teal-300"
|
||||
>
|
||||
Back to login
|
||||
</button>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue