project-standalo-sonic-cloud/components/AuthForm.tsx

210 lines
7.0 KiB
TypeScript

'use client'
import { useState } from 'react'
export type AuthMode = 'login' | 'register' | 'forgot-password'
export interface AuthFormProps {
mode: AuthMode
onSubmit: (data: AuthFormData) => void | Promise<void>
isLoading?: boolean
error?: string
onModeChange?: (mode: AuthMode) => void
}
export interface AuthFormData {
email: string
password?: string
username?: string
confirmPassword?: string
}
export function AuthForm({
mode,
onSubmit,
isLoading = false,
error,
onModeChange
}: AuthFormProps) {
const [formData, setFormData] = useState<AuthFormData>({
email: '',
password: '',
username: '',
confirmPassword: ''
})
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
onSubmit(formData)
}
const titles = {
login: 'Welcome back',
register: 'Create your account',
'forgot-password': 'Reset your password'
}
const buttonTexts = {
login: 'Sign in',
register: 'Create account',
'forgot-password': 'Send reset link'
}
return (
<div className="w-full max-w-md mx-auto">
<div className="bg-zinc-900 rounded-2xl p-8 shadow-2xl border border-zinc-800">
{/* Logo/Title */}
<div className="text-center mb-8">
<div className="w-16 h-16 mx-auto mb-4 rounded-full bg-purple-500 flex items-center justify-center">
<svg className="w-8 h-8 text-white" fill="currentColor" viewBox="0 0 20 20">
<path d="M18 3a1 1 0 00-1.196-.98l-10 2A1 1 0 006 5v9.114A4.369 4.369 0 005 14c-1.657 0-3 .895-3 2s1.343 2 3 2 3-.895 3-2V7.82l8-1.6v5.894A4.37 4.37 0 0015 12c-1.657 0-3 .895-3 2s1.343 2 3 2 3-.895 3-2V3z" />
</svg>
</div>
<h1 className="text-2xl font-bold text-white">{titles[mode]}</h1>
</div>
{/* Error Message */}
{error && (
<div className="mb-6 p-4 bg-red-500/10 border border-red-500/50 rounded-lg text-red-400 text-sm">
{error}
</div>
)}
{/* Form */}
<form onSubmit={handleSubmit} className="space-y-4">
{/* Username (Register only) */}
{mode === 'register' && (
<div>
<label htmlFor="username" className="block text-sm font-medium text-zinc-300 mb-2">
Username
</label>
<input
type="text"
id="username"
value={formData.username}
onChange={(e) => setFormData({ ...formData, username: e.target.value })}
className="w-full px-4 py-3 bg-zinc-800 border border-zinc-700 rounded-lg text-white placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-purple-500"
placeholder="Choose a username"
required
/>
</div>
)}
{/* Email */}
<div>
<label htmlFor="email" className="block text-sm font-medium text-zinc-300 mb-2">
Email
</label>
<input
type="email"
id="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
className="w-full px-4 py-3 bg-zinc-800 border border-zinc-700 rounded-lg text-white placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-purple-500"
placeholder="your@email.com"
required
/>
</div>
{/* Password (not in forgot-password) */}
{mode !== 'forgot-password' && (
<div>
<label htmlFor="password" className="block text-sm font-medium text-zinc-300 mb-2">
Password
</label>
<input
type="password"
id="password"
value={formData.password}
onChange={(e) => setFormData({ ...formData, password: e.target.value })}
className="w-full px-4 py-3 bg-zinc-800 border border-zinc-700 rounded-lg text-white placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-purple-500"
placeholder="••••••••"
required
/>
</div>
)}
{/* Confirm Password (Register only) */}
{mode === 'register' && (
<div>
<label htmlFor="confirmPassword" className="block text-sm font-medium text-zinc-300 mb-2">
Confirm Password
</label>
<input
type="password"
id="confirmPassword"
value={formData.confirmPassword}
onChange={(e) => setFormData({ ...formData, confirmPassword: e.target.value })}
className="w-full px-4 py-3 bg-zinc-800 border border-zinc-700 rounded-lg text-white placeholder-zinc-500 focus:outline-none focus:ring-2 focus:ring-purple-500"
placeholder="••••••••"
required
/>
</div>
)}
{/* Forgot Password Link (Login only) */}
{mode === 'login' && onModeChange && (
<div className="text-right">
<button
type="button"
onClick={() => onModeChange('forgot-password')}
className="text-sm text-purple-400 hover:text-purple-300"
>
Forgot password?
</button>
</div>
)}
{/* Submit Button */}
<button
type="submit"
disabled={isLoading}
className="w-full py-3 bg-purple-500 hover:bg-purple-600 disabled:bg-zinc-700 disabled:text-zinc-500 text-white font-semibold rounded-lg transition"
>
{isLoading ? 'Loading...' : buttonTexts[mode]}
</button>
</form>
{/* Mode Switch Links */}
{onModeChange && (
<div className="mt-6 text-center text-sm text-zinc-400">
{mode === 'login' && (
<p>
Don't have an account?{' '}
<button
onClick={() => onModeChange('register')}
className="text-purple-400 hover:text-purple-300 font-medium"
>
Sign up
</button>
</p>
)}
{mode === 'register' && (
<p>
Already have an account?{' '}
<button
onClick={() => onModeChange('login')}
className="text-purple-400 hover:text-purple-300 font-medium"
>
Sign in
</button>
</p>
)}
{mode === 'forgot-password' && (
<p>
Remember your password?{' '}
<button
onClick={() => onModeChange('login')}
className="text-purple-400 hover:text-purple-300 font-medium"
>
Sign in
</button>
</p>
)}
</div>
)}
</div>
</div>
)
}