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:
andupetcu
2025-09-21 01:06:30 +03:00
parent 62ca73b2ac
commit 196ca00194
174 changed files with 181207 additions and 179 deletions

View File

@@ -30,10 +30,12 @@ import {
Home,
Settings,
Logout,
Login,
} from '@mui/icons-material'
import { useRouter } from 'next/navigation'
import { useTranslations, useLocale } from 'next-intl'
import { LanguageSwitcher } from './language-switcher'
import { useAuth } from '@/hooks/use-auth'
export function Navigation() {
const [anchorElNav, setAnchorElNav] = useState<null | HTMLElement>(null)
@@ -44,6 +46,7 @@ export function Navigation() {
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
const t = useTranslations('navigation')
const locale = useLocale()
const { user, isAuthenticated, logout } = useAuth()
const pages = [
{ name: t('home'), path: '/', icon: <Home /> },
@@ -53,9 +56,9 @@ export function Navigation() {
]
const settings = [
{ name: t('profile'), icon: <AccountCircle /> },
{ name: t('settings'), icon: <Settings /> },
{ name: t('logout'), icon: <Logout /> },
{ name: t('profile'), icon: <AccountCircle />, action: 'profile' },
{ name: t('settings'), icon: <Settings />, action: 'settings' },
{ name: t('logout'), icon: <Logout />, action: 'logout' },
]
const handleOpenNavMenu = (event: React.MouseEvent<HTMLElement>) => {
@@ -81,6 +84,29 @@ export function Navigation() {
setDrawerOpen(false)
}
const handleUserMenuAction = (action: string) => {
handleCloseUserMenu()
switch (action) {
case 'profile':
router.push(`/${locale}/profile`)
break
case 'settings':
router.push(`/${locale}/settings`)
break
case 'logout':
logout()
router.push(`/${locale}`)
break
default:
break
}
}
const handleLogin = () => {
router.push(`/${locale}/auth/login`)
}
const toggleDrawer = (open: boolean) => {
setDrawerOpen(open)
}
@@ -191,38 +217,56 @@ export function Navigation() {
{/* User Menu */}
<Box sx={{ flexGrow: 0 }}>
<Tooltip title={t('settings')}>
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar sx={{ bgcolor: 'secondary.main' }}>
<AccountCircle />
</Avatar>
</IconButton>
</Tooltip>
<Menu
sx={{ mt: '45px' }}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
{settings.map((setting) => (
<MenuItem key={setting.name} onClick={handleCloseUserMenu}>
<ListItemIcon>
{setting.icon}
</ListItemIcon>
<Typography textAlign="center">{setting.name}</Typography>
</MenuItem>
))}
</Menu>
{isAuthenticated ? (
<>
<Tooltip title={user?.name || user?.email || t('profile')}>
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar sx={{ bgcolor: 'secondary.main' }}>
{user?.name ? user.name.charAt(0).toUpperCase() : <AccountCircle />}
</Avatar>
</IconButton>
</Tooltip>
<Menu
sx={{ mt: '45px' }}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
<MenuItem disabled>
<Typography variant="body2" color="text.secondary">
{user?.name || user?.email}
</Typography>
</MenuItem>
{settings.map((setting) => (
<MenuItem key={setting.name} onClick={() => handleUserMenuAction(setting.action)}>
<ListItemIcon>
{setting.icon}
</ListItemIcon>
<Typography textAlign="center">{setting.name}</Typography>
</MenuItem>
))}
</Menu>
</>
) : (
<Button
onClick={handleLogin}
variant="outlined"
startIcon={<Login />}
sx={{ color: 'white', borderColor: 'white', '&:hover': { borderColor: 'white', bgcolor: 'primary.dark' } }}
>
Login
</Button>
)}
</Box>
</Toolbar>
</Container>