lomavuokraus/app/components/NavBar.tsx
2025-11-24 17:15:20 +02:00

126 lines
4.3 KiB
TypeScript

'use client';
import Link from 'next/link';
import { useEffect, useState } from 'react';
import { useI18n } from './I18nProvider';
type SessionUser = { id: string; email: string; role: string; status: string };
export default function NavBar() {
const { t, locale, setLocale } = useI18n();
const [user, setUser] = useState<SessionUser | null>(null);
const [pendingCount, setPendingCount] = useState<number>(0);
async function loadUser() {
try {
const res = await fetch('/api/auth/me', { cache: 'no-store' });
const data = await res.json();
if (data.user) setUser(data.user);
else setUser(null);
} catch (e) {
setUser(null);
}
}
useEffect(() => {
loadUser();
}, []);
useEffect(() => {
const role = user?.role;
const canSeeApprovals = role === 'ADMIN' || role === 'LISTING_MODERATOR' || role === 'USER_MODERATOR';
if (!canSeeApprovals) {
setPendingCount(0);
return;
}
fetch('/api/admin/pending/count', { cache: 'no-store' })
.then((res) => res.json())
.then((data) => {
if (data && typeof data.total === 'number') setPendingCount(data.total);
})
.catch(() => setPendingCount(0));
}, [user]);
async function logout() {
try {
await fetch('/api/auth/logout', { method: 'POST' });
} catch (e) {
// ignore
}
setUser(null);
}
const isAdmin = user?.role === 'ADMIN';
const isListingMod = user?.role === 'LISTING_MODERATOR';
const isUserMod = user?.role === 'USER_MODERATOR';
const showApprovals = Boolean(user && (isAdmin || isListingMod || isUserMod));
return (
<header style={{ padding: '12px 20px', borderBottom: '1px solid #eee', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
<Link href="/" className="brand">
{t('brand')}
</Link>
<Link href="/listings" className="button secondary">
{t('navBrowse')}
</Link>
</div>
<nav style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
{user ? (
<>
<span style={{ fontSize: 12, color: '#444', border: '1px solid #ddd', borderRadius: 12, padding: '4px 10px' }}>
{user.email} · {user.role}
</span>
<Link href="/me" className="button secondary">
{t('navProfile')}
</Link>
<Link href="/listings/mine" className="button secondary">
{t('navMyListings')}
</Link>
<Link href="/listings/new" className="button secondary">
{t('navNewListing')}
</Link>
{showApprovals ? (
<>
<Link href="/admin/pending" className="button secondary">
{t('navApprovals')}
{pendingCount > 0 ? (
<span style={{ marginLeft: 6, background: '#ff7043', color: '#fff', borderRadius: 10, padding: '2px 6px', fontSize: 12 }}>
{t('approvalsBadge', { count: pendingCount })}
</span>
) : null}
</Link>
{isAdmin ? (
<Link href="/admin/users" className="button secondary">
{t('navUsers')}
</Link>
) : null}
</>
) : null}
<button className="button secondary" onClick={logout}>
{t('navLogout')}
</button>
</>
) : (
<>
<Link href="/auth/login" className="button secondary">
{t('navLogin')}
</Link>
<Link href="/auth/register" className="button">
{t('navSignup')}
</Link>
</>
)}
<div style={{ display: 'flex', alignItems: 'center', gap: 4, marginLeft: 8 }}>
<span style={{ fontSize: 12, color: '#555' }}>{t('navLanguage')}:</span>
<button className="button secondary" onClick={() => setLocale('fi')} style={{ padding: '4px 8px', opacity: locale === 'fi' ? 1 : 0.7 }}>
FI
</button>
<button className="button secondary" onClick={() => setLocale('en')} style={{ padding: '4px 8px', opacity: locale === 'en' ? 1 : 0.7 }}>
EN
</button>
</div>
</nav>
</header>
);
}