mirror of
https://github.com/azaion/ui.git
synced 2026-06-22 15:51:12 +00:00
Refactor project structure and dependencies; rename package to azaion-ui, update version to 0.0.1, and remove unused files. Introduce new routing and authentication features in App component.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { useState, type FormEvent } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useAuth } from '../../auth/AuthContext'
|
||||
|
||||
type UnlockStep = 'idle' | 'authenticating' | 'downloadingKey' | 'decrypting' | 'startingServices' | 'ready'
|
||||
|
||||
const STEP_KEYS: Record<UnlockStep, string> = {
|
||||
idle: '',
|
||||
authenticating: 'login.authenticating',
|
||||
downloadingKey: 'login.downloadingKey',
|
||||
decrypting: 'login.decrypting',
|
||||
startingServices: 'login.startingServices',
|
||||
ready: 'login.ready',
|
||||
}
|
||||
|
||||
export default function LoginPage() {
|
||||
const { t } = useTranslation()
|
||||
const { login } = useAuth()
|
||||
const navigate = useNavigate()
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
const [error, setError] = useState('')
|
||||
const [step, setStep] = useState<UnlockStep>('idle')
|
||||
|
||||
const runUnlockSequence = async () => {
|
||||
const steps: UnlockStep[] = ['downloadingKey', 'decrypting', 'startingServices', 'ready']
|
||||
for (const s of steps) {
|
||||
setStep(s)
|
||||
await new Promise(r => setTimeout(r, 600))
|
||||
}
|
||||
navigate('/flights')
|
||||
}
|
||||
|
||||
const handleSubmit = async (e: FormEvent) => {
|
||||
e.preventDefault()
|
||||
setError('')
|
||||
setStep('authenticating')
|
||||
try {
|
||||
await login(email, password)
|
||||
await runUnlockSequence()
|
||||
} catch {
|
||||
setStep('idle')
|
||||
setError(t('login.error'))
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen bg-az-bg">
|
||||
<form onSubmit={handleSubmit} className="bg-az-panel border border-az-border rounded-lg p-6 w-[400px] shadow-2xl">
|
||||
<h1 className="text-2xl font-bold text-az-orange text-center mb-6 tracking-widest">{t('login.title')}</h1>
|
||||
|
||||
{step !== 'idle' && (
|
||||
<div className="mb-4 text-center">
|
||||
<div className="inline-block animate-spin rounded-full h-6 w-6 border-2 border-az-orange border-t-transparent mb-2" />
|
||||
<div className="text-sm text-az-text">{t(STEP_KEYS[step])}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{step === 'idle' && (
|
||||
<>
|
||||
<div className="mb-3">
|
||||
<label className="block text-xs text-az-muted mb-1">{t('login.email')}</label>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
className="w-full bg-az-bg border border-az-border rounded px-3 py-2 text-az-text outline-none focus:border-az-orange"
|
||||
required
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<label className="block text-xs text-az-muted mb-1">{t('login.password')}</label>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
className="w-full bg-az-bg border border-az-border rounded px-3 py-2 text-az-text outline-none focus:border-az-orange"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{error && <div className="text-az-red text-sm mb-3">{error}</div>}
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full bg-az-orange text-white font-semibold py-2 rounded hover:bg-orange-600 transition"
|
||||
>
|
||||
{t('login.submit')}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user