feat: 登录/注册/邀请码激活弹窗
This commit is contained in:
parent
e26ae634b7
commit
8103bfd266
137
src/components/auth/LoginModal.tsx
Normal file
137
src/components/auth/LoginModal.tsx
Normal file
@ -0,0 +1,137 @@
|
||||
import { useState } from 'react'
|
||||
import { X } from 'lucide-react'
|
||||
import { apiLogin, apiRegister, apiActivate, setToken } from '../../lib/auth'
|
||||
import { useAppStore } from '../../stores/appStore'
|
||||
|
||||
type Tab = 'login' | 'register' | 'activate'
|
||||
|
||||
export function LoginModal({ onClose, initialTab }: { onClose: () => void; initialTab?: Tab }) {
|
||||
const [tab, setTab] = useState<Tab>(initialTab ?? 'login')
|
||||
const [username, setUsername] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [code, setCode] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const { setCurrentUser, syncFromCloud, currentUser } = useAppStore()
|
||||
|
||||
async function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
setLoading(true)
|
||||
try {
|
||||
if (tab === 'login') {
|
||||
const { token, user } = await apiLogin(username, password)
|
||||
setToken(token)
|
||||
setCurrentUser(user)
|
||||
if (user.cloudEnabled) await syncFromCloud()
|
||||
onClose()
|
||||
} else if (tab === 'register') {
|
||||
const { token, user } = await apiRegister(username, password)
|
||||
setToken(token)
|
||||
setCurrentUser(user)
|
||||
onClose()
|
||||
} else {
|
||||
await apiActivate(code)
|
||||
setCurrentUser({ ...currentUser!, cloudEnabled: true })
|
||||
await syncFromCloud()
|
||||
onClose()
|
||||
}
|
||||
} catch (err: any) {
|
||||
setError(err.message)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const inputStyle = {
|
||||
background: 'var(--bg-muted)',
|
||||
border: '1px solid var(--border)',
|
||||
color: 'var(--text)',
|
||||
width: '100%',
|
||||
padding: '0.5rem 0.75rem',
|
||||
borderRadius: '0.5rem',
|
||||
fontSize: '0.875rem',
|
||||
outline: 'none',
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center"
|
||||
style={{ background: 'rgba(0,0,0,0.5)' }}
|
||||
onClick={onClose}
|
||||
>
|
||||
<div
|
||||
className="rounded-2xl shadow-2xl p-6 w-80 flex flex-col gap-4"
|
||||
style={{ background: 'var(--bg)', border: '1px solid var(--border)' }}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-sm font-semibold" style={{ color: 'var(--text)' }}>
|
||||
{tab === 'login' ? '登录' : tab === 'register' ? '注册' : '激活云存储'}
|
||||
</h2>
|
||||
<button onClick={onClose} className="p-1 rounded" style={{ color: 'var(--text-faint)' }}>
|
||||
<X size={14} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{tab !== 'activate' && (
|
||||
<div className="flex gap-1 p-1 rounded-lg" style={{ background: 'var(--bg-muted)' }}>
|
||||
{(['login', 'register'] as Tab[]).map(t => (
|
||||
<button
|
||||
key={t}
|
||||
onClick={() => setTab(t)}
|
||||
className="flex-1 py-1 rounded text-xs font-medium transition-all"
|
||||
style={{
|
||||
background: tab === t ? 'var(--bg)' : 'transparent',
|
||||
color: tab === t ? 'var(--text)' : 'var(--text-faint)',
|
||||
}}
|
||||
>
|
||||
{t === 'login' ? '登录' : '注册'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<form onSubmit={handleSubmit} className="flex flex-col gap-3">
|
||||
{tab !== 'activate' ? (
|
||||
<>
|
||||
<input
|
||||
style={inputStyle}
|
||||
placeholder="用户名"
|
||||
value={username}
|
||||
onChange={e => setUsername(e.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
<input
|
||||
style={inputStyle}
|
||||
type="password"
|
||||
placeholder="密码(至少 6 位)"
|
||||
value={password}
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<input
|
||||
style={inputStyle}
|
||||
placeholder="邀请码(如 MIKI-A7X2-KP9Q)"
|
||||
value={code}
|
||||
onChange={e => setCode(e.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
)}
|
||||
|
||||
{error && <p className="text-xs" style={{ color: '#ef4444' }}>{error}</p>}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className="w-full py-2 rounded-lg text-sm font-medium"
|
||||
style={{ background: 'var(--accent)', color: '#fff', opacity: loading ? 0.7 : 1 }}
|
||||
>
|
||||
{loading ? '请稍候…' : tab === 'login' ? '登录' : tab === 'register' ? '注册' : '激活'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user