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:
Oleksandr Bezdieniezhnykh
2026-03-25 03:10:15 +02:00
parent e407308284
commit 157a33096a
112 changed files with 6530 additions and 17843 deletions
+95
View File
@@ -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>
)
}