Fix authentication state persistence and admin role display
- Implement complete authentication system with JWT token validation - Add auth provider with persistent login state across page refreshes - Create multilingual login/register forms with Material-UI components - Fix token validation using raw SQL queries to bypass Prisma sync issues - Add comprehensive error handling for expired/invalid tokens - Create profile and settings pages with full i18n support - Add proper user role management (admin/user) with database sync - Implement secure middleware with CSRF protection and auth checks - Add debug endpoints for troubleshooting authentication issues - Fix Zustand store persistence for authentication state 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
133
app/[locale]/auth/login/page.tsx
Normal file
133
app/[locale]/auth/login/page.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useTranslations, useLocale } from 'next-intl'
|
||||
import {
|
||||
Container,
|
||||
Paper,
|
||||
Box,
|
||||
Typography,
|
||||
Tabs,
|
||||
Tab,
|
||||
Link,
|
||||
Card,
|
||||
CardContent,
|
||||
Divider
|
||||
} from '@mui/material'
|
||||
import {
|
||||
MenuBook,
|
||||
Login as LoginIcon,
|
||||
PersonAdd
|
||||
} from '@mui/icons-material'
|
||||
import { LoginForm } from '@/components/auth/login-form'
|
||||
import { RegisterForm } from '@/components/auth/register-form'
|
||||
|
||||
export default function AuthPage() {
|
||||
const [activeTab, setActiveTab] = useState(0)
|
||||
const router = useRouter()
|
||||
const locale = useLocale()
|
||||
const t = useTranslations('auth')
|
||||
|
||||
const handleAuthSuccess = () => {
|
||||
router.push(`/${locale}`)
|
||||
}
|
||||
|
||||
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
|
||||
setActiveTab(newValue)
|
||||
}
|
||||
|
||||
const getSubtitle = () => {
|
||||
if (locale === 'en') {
|
||||
return activeTab === 0
|
||||
? 'Sign in to continue exploring Scripture'
|
||||
: 'Create an account to begin your spiritual journey'
|
||||
}
|
||||
return activeTab === 0
|
||||
? 'Conectează-te pentru a continua explorarea Scripturii'
|
||||
: 'Creează un cont pentru a începe călătoria ta spirituală'
|
||||
}
|
||||
|
||||
return (
|
||||
<Container maxWidth="sm" sx={{ py: 4, minHeight: '100vh', display: 'flex', alignItems: 'center' }}>
|
||||
<Card elevation={8} sx={{ width: '100%', borderRadius: 3 }}>
|
||||
<CardContent sx={{ p: 4 }}>
|
||||
{/* Header */}
|
||||
<Box textAlign="center" mb={4}>
|
||||
<Box display="flex" justifyContent="center" mb={2}>
|
||||
<MenuBook sx={{ fontSize: 48, color: 'primary.main' }} />
|
||||
</Box>
|
||||
<Typography variant="h4" component="h1" gutterBottom fontWeight="bold">
|
||||
{activeTab === 0 ? t('welcomeBack') : t('joinUs')}
|
||||
</Typography>
|
||||
<Typography variant="body1" color="text.secondary">
|
||||
{getSubtitle()}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ mb: 3 }} />
|
||||
|
||||
{/* Tabs */}
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onChange={handleTabChange}
|
||||
centered
|
||||
sx={{
|
||||
mb: 3,
|
||||
'& .MuiTab-root': {
|
||||
minWidth: 120,
|
||||
fontWeight: 600
|
||||
}
|
||||
}}
|
||||
TabIndicatorProps={{
|
||||
style: { height: 3, borderRadius: 3 }
|
||||
}}
|
||||
>
|
||||
<Tab
|
||||
icon={<LoginIcon />}
|
||||
iconPosition="start"
|
||||
label={t('login')}
|
||||
/>
|
||||
<Tab
|
||||
icon={<PersonAdd />}
|
||||
iconPosition="start"
|
||||
label={t('register')}
|
||||
/>
|
||||
</Tabs>
|
||||
|
||||
{/* Forms */}
|
||||
<Box sx={{ minHeight: 300 }}>
|
||||
{activeTab === 0 ? (
|
||||
<LoginForm onSuccess={handleAuthSuccess} />
|
||||
) : (
|
||||
<RegisterForm onSuccess={handleAuthSuccess} />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ my: 3 }} />
|
||||
|
||||
{/* Switch Form Link */}
|
||||
<Box textAlign="center">
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{activeTab === 0 ? t('noAccount') : t('alreadyHaveAccount')}{' '}
|
||||
<Link
|
||||
component="button"
|
||||
variant="body2"
|
||||
onClick={() => setActiveTab(activeTab === 0 ? 1 : 0)}
|
||||
sx={{
|
||||
textDecoration: 'none',
|
||||
fontWeight: 600,
|
||||
'&:hover': {
|
||||
textDecoration: 'underline'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{activeTab === 0 ? t('createAccount') : t('login')}
|
||||
</Link>
|
||||
</Typography>
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user