turash/bugulma/frontend/pages/LoginPage.tsx
Damir Mukimov 02fad6713c refactor(docs/locales): rename project from 'Tуган Як'/'Tugan Yak' to 'Turash' across docs, locales and test fixtures
- Update locales (ru, tt, en) to use 'Turash' and 'Turash AI'
- Update metadata, index.html, and pixel-art README
- Replace example credentials/emails from @tuganyak.dev -> @turash.dev
- Update admin defaults and migration seed to use new admin@turash.dev
- Update docs mentioning the old name
2025-12-15 05:42:16 +01:00

205 lines
7.3 KiB
TypeScript

import { MainLayout } from '@/components/layout/MainLayout';
import PageHeader from '@/components/layout/PageHeader';
import { Badge } from '@/components/ui';
import Button from '@/components/ui/Button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card';
import Input from '@/components/ui/Input';
import { useAuth } from '@/contexts/AuthContext';
import { useTranslation } from '@/hooks/useI18n';
import { useNavigation } from '@/hooks/useNavigation';
import { Eye, FileText, Shield, User } from 'lucide-react';
import React, { useEffect, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
const isDevelopment = import.meta.env.DEV;
// Test user credentials for development
const TEST_USERS = [
{
email: 'admin@turash.dev',
password: 'admin123',
role: 'admin',
label: 'Admin',
icon: <Shield className="h-4 w-4" />,
description: 'Full admin panel access',
},
{
email: 'user@turash.dev',
password: 'user12345',
role: 'user',
label: 'User',
icon: <User className="h-4 w-4" />,
description: 'Regular user dashboard',
},
{
email: 'content@turash.dev',
password: 'content123',
role: 'content_manager',
label: 'Content Manager',
icon: <FileText className="h-4 w-4" />,
description: 'Content and localization',
},
{
email: 'viewer@turash.dev',
password: 'viewer123',
role: 'viewer',
label: 'Viewer',
icon: <Eye className="h-4 w-4" />,
description: 'Read-only access',
},
] as const;
const LoginPage = () => {
const { t } = useTranslation();
const { login, isLoading, user } = useAuth();
const { handleFooterNavigate } = useNavigation();
const navigate = useNavigate();
const [email, setEmail] = useState(isDevelopment ? 'admin@turash.dev' : '');
const [password, setPassword] = useState(isDevelopment ? 'admin123' : '');
const [error, setError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
try {
await login(email, password);
// Navigation will happen after user state is updated
// We'll use useEffect to handle navigation
} catch (err) {
setError(err instanceof Error ? err.message : 'Login failed');
}
};
const handleQuickLogin = async (testUser: (typeof TEST_USERS)[number]) => {
setError('');
setEmail(testUser.email);
setPassword(testUser.password);
try {
await login(testUser.email, testUser.password);
// Navigation will happen after user state is updated
} catch (err) {
setError(err instanceof Error ? err.message : 'Login failed');
}
};
// Navigate after successful login
useEffect(() => {
if (user && !isLoading) {
if (user.role === 'admin') {
navigate('/admin');
} else {
navigate('/dashboard');
}
}
}, [user, isLoading, navigate]);
return (
<MainLayout onNavigate={handleFooterNavigate}>
<div className="mx-auto max-w-md px-4 py-8 sm:py-12">
<PageHeader title={t('loginPage.title')} />
<Card>
<CardHeader>
<CardTitle>{t('loginPage.subtitle')}</CardTitle>
</CardHeader>
<CardContent>
{isDevelopment && (
<div className="mb-6 p-4 bg-muted rounded-lg border border-primary/20">
<p className="text-sm font-medium mb-3 text-foreground">
Quick Login (Development)
</p>
<div className="grid grid-cols-2 gap-2">
{TEST_USERS.map((testUser) => (
<Button
key={testUser.email}
type="button"
variant="outline"
size="sm"
onClick={() => handleQuickLogin(testUser)}
disabled={isLoading}
className="flex flex-col items-start h-auto py-2 px-3"
>
<div className="flex items-center gap-2 w-full">
{testUser.icon}
<span className="font-medium text-xs">{testUser.label}</span>
</div>
<span className="text-xs text-muted-foreground mt-1">
{testUser.description}
</span>
</Button>
))}
</div>
<div className="mt-3 pt-3 border-t border-border">
<p className="text-xs text-muted-foreground mb-2">Test Credentials:</p>
<div className="space-y-1 text-xs font-mono">
{TEST_USERS.map((user) => (
<div key={user.email} className="flex items-center gap-2">
<Badge variant="outline" className="text-xs px-1.5 py-0">
{user.role}
</Badge>
<span className="text-muted-foreground">{user.email}</span>
<span className="text-muted-foreground">/</span>
<span className="text-muted-foreground">{user.password}</span>
</div>
))}
</div>
</div>
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="email" className="block text-sm font-medium text-foreground mb-1">
{t('loginPage.email')}
</label>
<Input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
placeholder={isDevelopment ? 'admin@turash.dev' : 'your@email.com'}
/>
</div>
<div>
<label
htmlFor="password"
className="block text-sm font-medium text-foreground mb-1"
>
{t('loginPage.password')}
</label>
<Input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
placeholder={isDevelopment ? 'admin123' : '••••••••'}
/>
</div>
{error && (
<div className="text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded px-3 py-2">
{error}
</div>
)}
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? t('loginPage.loading') : t('loginPage.login')}
</Button>
</form>
<div className="mt-4 text-sm text-muted-foreground text-center space-y-2">
{!isDevelopment && <div>{t('loginPage.demoNote')}</div>}
<div>
{t('loginPage.noAccount', "Don't have an account?")}{' '}
<Link to="/signup" className="text-primary hover:underline font-medium">
{t('loginPage.signupLink')}
</Link>
</div>
</div>
</CardContent>
</Card>
</div>
</MainLayout>
);
};
export default LoginPage;