Files
portaldata/components/ui/Navbar.tsx
Randa Firman Putra e028039ee2 First commit
2025-06-18 22:03:32 +07:00

375 lines
12 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
import { ThemeToggle } from '@/components/theme-toggle';
import { Menu, User } from 'lucide-react';
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
import SidebarContent from '@/components/ui/SidebarContent';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { useToast } from '@/components/ui/use-toast';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
const Navbar = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [dialogOpen, setDialogOpen] = useState(false);
const [loginData, setLoginData] = useState({ nim: '', password: '' });
const [registerData, setRegisterData] = useState({ username: '', nim: '', password: '', confirmPassword: '' });
const [userData, setUserData] = useState<any>(null);
const { toast } = useToast();
const router = useRouter();
// Check login status on component mount and when route changes
useEffect(() => {
const checkAuth = async () => {
try {
const response = await fetch('/api/auth/check');
const data = await response.json();
if (response.ok && data.user) {
setUserData(data.user);
setIsLoggedIn(true);
} else {
setUserData(null);
setIsLoggedIn(false);
}
} catch (error) {
console.error('Auth check failed:', error);
setUserData(null);
setIsLoggedIn(false);
}
};
checkAuth();
}, [router]);
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
// Validate input
if (!loginData.nim || !loginData.password) {
toast({
variant: "destructive",
title: "Login gagal",
description: "NIM dan password harus diisi",
});
return;
}
console.log('Login attempt with data:', {
nim: loginData.nim,
password: '***'
});
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
nim: loginData.nim.trim(),
password: loginData.password
}),
});
console.log('Login response status:', response.status);
const data = await response.json();
console.log('Login response data:', data);
if (!response.ok) {
throw new Error(data.error || 'Login gagal');
}
toast({
title: "Login berhasil",
description: "Selamat datang kembali!",
});
setUserData(data.user);
setIsLoggedIn(true);
setDialogOpen(false);
router.refresh();
} catch (error) {
console.error('Login error:', error);
toast({
variant: "destructive",
title: "Login gagal",
description: error instanceof Error ? error.message : 'Terjadi kesalahan saat login',
});
}
};
const handleRegister = async (e: React.FormEvent) => {
e.preventDefault();
// Validate passwords match
if (registerData.password !== registerData.confirmPassword) {
toast({
variant: "destructive",
title: "Registrasi gagal",
description: "Password dan konfirmasi password tidak cocok",
});
return;
}
try {
const response = await fetch('/api/auth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: registerData.username,
nim: registerData.nim,
password: registerData.password,
}),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Registrasi gagal');
}
toast({
title: "Registrasi berhasil",
description: "Silakan login dengan akun Anda",
});
// Reset form and switch to login tab
setRegisterData({ username: '', nim: '', password: '', confirmPassword: '' });
const tabsList = document.querySelector('[role="tablist"]');
if (tabsList) {
const loginTab = tabsList.querySelector('[value="login"]');
if (loginTab) {
(loginTab as HTMLElement).click();
}
}
} catch (error) {
toast({
variant: "destructive",
title: "Registrasi gagal",
description: error instanceof Error ? error.message : 'Terjadi kesalahan saat registrasi',
});
}
};
const handleLogout = async () => {
try {
const response = await fetch('/api/auth/logout', {
method: 'POST',
});
if (!response.ok) {
throw new Error('Logout gagal');
}
toast({
title: "Logout berhasil",
description: "Sampai jumpa lagi!",
});
setUserData(null);
setIsLoggedIn(false);
router.push('/');
router.refresh();
} catch (error) {
toast({
variant: "destructive",
title: "Logout gagal",
description: error instanceof Error ? error.message : 'Terjadi kesalahan saat logout',
});
}
};
const handleProfileClick = async () => {
try {
const response = await fetch('/api/auth/check');
const data = await response.json();
if (response.ok && data.user) {
router.push('/mahasiswa/profile');
} else {
toast({
variant: "destructive",
title: "Akses Ditolak",
description: "Silakan login terlebih dahulu untuk mengakses profil",
});
setDialogOpen(true);
router.push('/'); // Redirect to home if not logged in
}
} catch (error) {
console.error('Error checking auth status:', error);
toast({
variant: "destructive",
title: "Error",
description: "Terjadi kesalahan saat memeriksa status login",
});
router.push('/');
}
};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
if (name.startsWith('login')) {
const loginField = name.replace('login', '').toLowerCase();
setLoginData(prev => ({
...prev,
[loginField]: value
}));
} else {
setRegisterData(prev => ({
...prev,
[name]: value
}));
}
};
return (
<div className="bg-background border-b sticky top-0 z-50 py-2 px-5 flex justify-between items-center">
<div className="flex items-center gap-2">
{/* 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">
<DialogTitle className="sr-only">Menu Navigasi</DialogTitle>
<SidebarContent />
</SheetContent>
</Sheet>
</div>
<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>
<div className="flex items-center gap-4">
{isLoggedIn ? (
<DropdownMenu>
<DropdownMenuTrigger className="focus:outline-none">
<Avatar>
<AvatarImage src="" alt={userData?.username || 'User'} />
<AvatarFallback className="bg-primary/10">
<User className="h-5 w-5" />
</AvatarFallback>
</Avatar>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" side="bottom" sideOffset={9} alignOffset={0}>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={handleProfileClick}>
Profile
</DropdownMenuItem>
<DropdownMenuItem onClick={handleLogout}>Logout</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
) : (
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
<DialogTrigger asChild>
<Button variant="secondary">
Login
</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>Portal Data Informatika</DialogTitle>
<DialogDescription>Masuk atau daftar untuk mengakses portal</DialogDescription>
</DialogHeader>
<Tabs defaultValue="login" className="w-full mt-4">
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="login">Login</TabsTrigger>
<TabsTrigger value="register">Register</TabsTrigger>
</TabsList>
<TabsContent value="login">
<form onSubmit={handleLogin} className="space-y-4">
<Input
type="text"
name="loginNim"
placeholder="NIM"
value={loginData.nim}
onChange={handleInputChange}
required
/>
<Input
type="password"
name="loginPassword"
placeholder="Password"
value={loginData.password}
onChange={handleInputChange}
required
/>
<Button className="w-full" type="submit">
Login
</Button>
</form>
</TabsContent>
<TabsContent value="register">
<form onSubmit={handleRegister} className="space-y-4">
<Input
type="text"
name="username"
placeholder="Nama Lengkap"
value={registerData.username}
onChange={handleInputChange}
required
/>
<Input
type="text"
name="nim"
placeholder="NIM"
value={registerData.nim}
onChange={handleInputChange}
required
/>
<Input
type="password"
name="password"
placeholder="Password"
value={registerData.password}
onChange={handleInputChange}
required
/>
<Input
type="password"
name="confirmPassword"
placeholder="Konfirmasi Password"
value={registerData.confirmPassword}
onChange={handleInputChange}
required
/>
<Button className="w-full" type="submit">
Register
</Button>
</form>
</TabsContent>
</Tabs>
</DialogContent>
</Dialog>
)}
<ThemeToggle />
</div>
</div>
);
};
export default Navbar;