Files
portaldata/components/ui/Navbar.tsx
Randa Firman Putra 781a7c1be3 logout secure
2025-12-08 02:01:25 +07:00

384 lines
16 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { ThemeToggle } from '@/components/theme-toggle';
import { Menu, ChevronDown, BarChart, Database, GraduationCap, BookOpen, Award, LogOut, User, Users, BookOpenText } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import Link from 'next/link';
import { useToast } from '@/components/ui/toast-provider';
interface UserData {
id_user: number;
username?: string;
nip?: string;
role_user: string;
}
const Navbar = () => {
const [user, setUser] = useState<UserData | null>(null);
const [isVisible, setIsVisible] = useState(true);
const [lastScrollY, setLastScrollY] = useState(0);
const { showSuccess, showError } = useToast ();
const router = useRouter();
// Check for existing user session on mount
useEffect(() => {
checkUserSession();
}, []);
// Handle scroll behavior
useEffect(() => {
const controlNavbar = () => {
if (typeof window !== 'undefined') {
if (window.scrollY > lastScrollY && window.scrollY > 100) {
// Scrolling down & past 100px
setIsVisible(false);
} else {
// Scrolling up
setIsVisible(true);
}
setLastScrollY(window.scrollY);
}
};
if (typeof window !== 'undefined') {
window.addEventListener('scroll', controlNavbar);
return () => {
window.removeEventListener('scroll', controlNavbar);
};
}
}, [lastScrollY]);
const checkUserSession = async () => {
try {
const response = await fetch('/api/auth/user');
console.log('Session check response:', response.status);
if (response.ok) {
const data = await response.json();
console.log('User data:', data);
setUser(data.user);
} else {
console.log('No session found or session check failed');
}
} catch (error) {
console.error('Error checking session:', error);
}
};
const handleLoginSuccess = (userData: any) => {
setUser(userData.user);
};
const handleLogout = async () => {
try {
const response = await fetch('/api/auth/logout', {
method: 'POST',
});
if (response.ok) {
setUser(null);
showSuccess("Berhasil!", "Anda telah keluar dari sistem");
// Redirect to root page after successful logout - using window.location for hard redirect
setTimeout(() => {
window.location.href = '/';
}, 500); // Small delay to show toast notification
}
} catch (error) {
console.error('Logout error:', error);
showError("Gagal!", "Terjadi kesalahan saat logout");
}
};
return (
<div className={`bg-background/95 border-b py-2 sticky top-0 z-30 transition-transform duration-300 ${
isVisible ? 'translate-y-0' : '-translate-y-full'
}`}>
<div className="container mx-auto px-4 flex justify-between items-center">
{/* Logo */}
<div className="flex items-center">
<Link href="/" className="flex items-center text-lg font-semibold hover:text-primary transition-colors">
<img src="/podif-icon.png" alt="PODIF Logo" className="h-6 w-auto mr-2" />
PODIF
</Link>
</div>
{/* Desktop Navigation - Centered */}
<div className="hidden md:flex items-center gap-4">
{/* Dashboard - Only for Ketua Jurusan */}
{user && (user.role_user === 'ketuajurusan' || user.role_user === 'ketuaprodi') && (
<>
<Link href="/dashboard" className="flex items-center gap-2 px-3 py-2 text-sm font-medium hover:text-primary transition-colors">
<BarChart className="h-4 w-4" />
Dashboard
</Link>
{/* <DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="flex items-center gap-2 px-3 py-2 text-sm font-medium">
<BarChart className="h-4 w-4" />
Visualisasi
<ChevronDown className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="center" className="w-48">
<DropdownMenuItem asChild>
<Link href="/visualisasi/dashboard" className="flex items-center gap-2 w-full">
<GraduationCap className="h-4 w-4" />
Dashboard Mahasiswa
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/visualisasi/mahasiswa" className="flex items-center gap-2 w-full">
<GraduationCap className="h-4 w-4" />
Mahasiswa
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/visualisasi/status" className="flex items-center gap-2 w-full">
<CircleCheck className="h-4 w-4" />
Status Kuliah
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/visualisasi/lulustepatwaktu" className="flex items-center gap-2 w-full">
<Clock className="h-4 w-4" />
Lulus Tepat Waktu
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/visualisasi/beasiswa" className="flex items-center gap-2 w-full">
<BookOpen className="h-4 w-4" />
Beasiswa
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/visualisasi/berprestasi" className="flex items-center gap-2 w-full">
<Award className="h-4 w-4" />
Prestasi
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu> */}
</>
)}
{/* Kelola Data Dropdown - Only for Admin */}
{user && user.role_user === 'admin' && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="flex items-center gap-2 px-3 py-2 text-sm font-medium">
<Database className="h-4 w-4" />
Kelola Data
<ChevronDown className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="center" className="w-48">
<DropdownMenuItem asChild>
<Link href="/keloladata/mahasiswa" className="flex items-center gap-2 w-full">
<GraduationCap className="h-4 w-4" />
Mahasiswa
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/keloladata/beasiswa" className="flex items-center gap-2 w-full">
<BookOpen className="h-4 w-4" />
Beasiswa
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/keloladata/prestasi" className="flex items-center gap-2 w-full">
<Award className="h-4 w-4" />
Prestasi
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/keloladata/dosen" className="flex items-center gap-2 w-full">
<Users className="h-4 w-4" />
Dosen
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/keloladata/matakuliah" className="flex items-center gap-2 w-full">
<BookOpen className="h-4 w-4" />
Mata Kuliah
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/keloladata/nilaimahasiswa" className="flex items-center gap-2 w-full">
<BookOpenText className="h-4 w-4" />
Nilai Mahasiswa
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<Link href="/keloladata/akun" className="flex items-center gap-2 w-full">
<User className="h-4 w-4" />
Akun
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)}
</div>
{/* Right Side - Theme Toggle, User Menu, and Mobile Menu */}
<div className="flex items-center gap-4">
{user && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="flex items-center gap-2">
<User className="h-4 w-4" />
{user.role_user === 'ketuajurusan'
? 'Ketua Jurusan'
: user.role_user === 'ketuaprodi'
? 'Ketua Prodi'
: 'Admin'}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem disabled>
<User className="h-4 w-4 mr-2" />
{user.username}
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={handleLogout}>
<LogOut className="h-4 w-4 mr-2" />
Logout
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)}
<ThemeToggle />
{/* Mobile Menu Button */}
<div className="md:hidden">
<Sheet>
<SheetTrigger asChild>
<Button variant="outline" size="icon">
<Menu className="h-5 w-5" />
<span className="sr-only">Toggle menu</span>
</Button>
</SheetTrigger>
<SheetContent side="left" className="p-0 w-[250px] overflow-y-auto">
<MobileNavContent user={user} onLogout={handleLogout} />
</SheetContent>
</Sheet>
</div>
</div>
</div>
</div>
);
};
// Mobile Navigation Content Component
interface MobileNavContentProps {
user: UserData | null;
onLogout: () => void;
}
const MobileNavContent = ({ user, onLogout }: MobileNavContentProps) => {
return (
<div className="p-4 space-y-4">
<div className="space-y-2">
<h3 className="text-sm font-semibold text-muted-foreground">Dashboard PODIF</h3>
</div>
{user ? (
<div className="space-y-2">
<h3 className="text-sm font-semibold text-muted-foreground">Menu Utama</h3>
{/* Dashboard - Only for Ketua Jurusan */}
{(user.role_user === 'ketuajurusan' || user.role_user === 'ketuaprodi') && (
<Link href="/dashboard" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<BarChart className="h-4 w-4" />
Dashboard
</Link>
)}
{/* <div className="space-y-1">
<h4 className="text-xs font-medium text-muted-foreground px-3">Visualisasi</h4>
<Link href="/visualisasi/mahasiswa" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<GraduationCap className="h-4 w-4" />
Mahasiswa
</Link>
<Link href="/visualisasi/status" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<CircleCheck className="h-4 w-4" />
Status Kuliah
</Link>
<Link href="/visualisasi/lulustepatwaktu" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<Clock className="h-4 w-4" />
Lulus Tepat Waktu
</Link>
<Link href="/visualisasi/beasiswa" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<BookOpen className="h-4 w-4" />
Beasiswa
</Link>
<Link href="/visualisasi/berprestasi" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<Award className="h-4 w-4" />
Prestasi
</Link>
</div> */}
{/* Kelola Data - Only for Admin */}
{user.role_user === 'admin' && (
<div className="space-y-1">
<h4 className="text-xs font-medium text-muted-foreground px-3">Kelola Data</h4>
<Link href="/keloladata/mahasiswa" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<GraduationCap className="h-4 w-4" />
Mahasiswa
</Link>
<Link href="/keloladata/beasiswa" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<BookOpen className="h-4 w-4" />
Beasiswa
</Link>
<Link href="/keloladata/prestasi" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<Award className="h-4 w-4" />
Prestasi
</Link>
<Link href="/keloladata/dosen" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<Users className="h-4 w-4" />
Dosen
</Link>
<Link href="/keloladata/matakuliah" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<BookOpen className="h-4 w-4" />
Mata Kuliah
</Link>
<Link href="/keloladata/nilaimahasiswa" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<BookOpenText className="h-4 w-4" />
Nilai Mahasiswa
</Link>
<Link href="/keloladata/akun" className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors">
<User className="h-4 w-4" />
Akun
</Link>
</div>
)}
<div className="pt-4 border-t">
<div className="flex items-center gap-2 px-3 py-2 text-sm text-muted-foreground">
<User className="h-4 w-4" />
{user.role_user === 'ketuajurusan' ? 'Ketua Jurusan' : 'Admin'}
</div>
<button
onClick={onLogout}
className="flex items-center gap-2 px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground rounded-md transition-colors w-full text-left"
>
<LogOut className="h-4 w-4" />
Logout
</button>
</div>
</div>
) : null}
</div>
);
};
export default Navbar;