OwnGPT.v2 / client /src /components /UI /AuthDialogPanel.jsx
parthib07's picture
Upload 199 files
212c959 verified
import { useEffect, useState } from 'react'
import {
ArrowRight,
Eye,
EyeOff,
Globe,
Loader2,
LockKeyhole,
Sparkles,
UserRound,
} from 'lucide-react'
import Modal from './Modal'
import Button from './Button'
export default function AuthDialogPanel({
open,
mode,
onModeChange,
onClose,
onLogin,
onRegister,
onGoogleLogin,
pending,
}) {
const [name, setName] = useState('')
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
const [showPassword, setShowPassword] = useState(false)
const isRegister = mode === 'register'
const submitLabel = isRegister ? 'Create account' : 'Sign in'
useEffect(() => {
setError('')
setShowPassword(false)
}, [mode, open])
const submit = async (event) => {
event.preventDefault()
setError('')
if (!username || !password || (isRegister && !name.trim())) {
setError('Fill all fields.')
return
}
try {
if (isRegister) {
await onRegister({ username, name: name.trim(), password })
} else {
await onLogin({ username, password })
}
} catch (authError) {
setError(authError.message || 'Authentication failed.')
}
}
return (
<Modal
open={open}
onOpenChange={(next) => {
if (!next) onClose()
}}
size="sm"
title={isRegister ? 'Create account' : 'Sign in'}
className="auth-panel border-border bg-card"
>
<div className="relative space-y-5 overflow-hidden">
<div className="auth-sweep" />
<div className="relative flex justify-center">
<div className="flex h-11 w-11 items-center justify-center rounded-lg bg-secondary text-muted-foreground">
<Sparkles className="h-5 w-5" />
</div>
</div>
<div className="relative grid grid-cols-2 gap-1 rounded-lg bg-panel p-1">
<button
type="button"
onClick={() => onModeChange('login')}
className={`rounded-lg px-4 py-2 text-sm font-medium transition ${
mode === 'login'
? 'bg-background text-foreground'
: 'text-muted-foreground hover:text-foreground'
}`}
>
Login
</button>
<button
type="button"
onClick={() => onModeChange('register')}
className={`rounded-lg px-4 py-2 text-sm font-medium transition ${
mode === 'register'
? 'bg-background text-foreground'
: 'text-muted-foreground hover:text-foreground'
}`}
>
Register
</button>
</div>
<Button
variant="secondary"
className="relative h-11 w-full justify-between"
onClick={onGoogleLogin}
disabled={pending}
>
<span className="inline-flex items-center gap-2">
<Globe className="h-4 w-4" />
Google
</span>
<ArrowRight className="h-4 w-4" />
</Button>
<form className="relative space-y-3" onSubmit={submit}>
{isRegister ? (
<AuthField
icon={UserRound}
label="Name"
value={name}
onChange={setName}
placeholder="Your name"
autoComplete="name"
/>
) : null}
<AuthField
icon={UserRound}
label="Username"
value={username}
onChange={setUsername}
placeholder="Username"
autoComplete="username"
autoFocus
/>
<label className="block space-y-1.5">
<span className="text-sm font-medium text-foreground">Password</span>
<div className="flex items-center gap-3 rounded-lg border border-input bg-panel px-3 py-2.5 transition focus-within:border-accent/50 focus-within:ring-2 focus-within:ring-ring/20">
<LockKeyhole className="h-4 w-4 shrink-0 text-muted-foreground" />
<input
type={showPassword ? 'text' : 'password'}
className="w-full bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
value={password}
onChange={(event) => setPassword(event.target.value)}
placeholder="Password"
autoComplete={isRegister ? 'new-password' : 'current-password'}
/>
<button
type="button"
onClick={() => setShowPassword((current) => !current)}
className="rounded-lg p-1 text-muted-foreground transition hover:bg-secondary hover:text-foreground"
aria-label={showPassword ? 'Hide password' : 'Show password'}
>
{showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</button>
</div>
</label>
{error ? (
<div className="rounded-lg border border-danger/25 bg-danger/10 px-3 py-2 text-sm text-danger">
{error}
</div>
) : null}
<Button type="submit" variant="primary" className="h-11 w-full" loading={pending}>
{pending ? <Loader2 className="h-4 w-4 animate-spin" /> : null}
{submitLabel}
</Button>
</form>
</div>
</Modal>
)
}
function AuthField({
icon: Icon,
label,
value,
onChange,
placeholder,
autoComplete,
autoFocus = false,
}) {
return (
<label className="block space-y-1.5">
<span className="text-sm font-medium text-foreground">{label}</span>
<div className="flex items-center gap-3 rounded-lg border border-input bg-panel px-3 py-2.5 transition focus-within:border-accent/50 focus-within:ring-2 focus-within:ring-ring/20">
<Icon className="h-4 w-4 shrink-0 text-muted-foreground" />
<input
className="w-full bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
value={value}
onChange={(event) => onChange(event.target.value)}
placeholder={placeholder}
autoComplete={autoComplete}
autoFocus={autoFocus}
/>
</div>
</label>
)
}