Files
portaldata/app/page.tsx
2025-12-08 17:57:52 +07:00

334 lines
11 KiB
TypeScript

'use client';
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { useTheme } from "next-themes";
import { useToast } from "@/components/ui/toast-provider";
interface UserData {
id_user: number;
username?: string;
nip?: string;
role_user: string;
}
export default function HomePage() {
const { theme } = useTheme();
const router = useRouter();
const { showSuccess, showError } = useToast();
const [user, setUser] = useState<UserData | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [showLoginDialog, setShowLoginDialog] = useState(false);
// Check for existing user session on mount
useEffect(() => {
checkUserSession();
}, []);
const checkUserSession = async () => {
try {
const response = await fetch('/api/auth/user');
if (response.ok) {
const data = await response.json();
setUser(data.user);
// Redirect based on user role
if (data.user.role_user === 'ketuajurusan' || data.user.role_user === 'ketuaprodi') {
router.push('/dashboard');
} else if (data.user.role_user === 'admin') {
router.push('/keloladata/mahasiswa');
}
} else {
// No user session, show login dialog
setShowLoginDialog(true);
}
} catch (error) {
console.error('Error checking session:', error);
setShowLoginDialog(true);
} finally {
setIsLoading(false);
}
};
const handleLoginSuccess = (userData: any) => {
setUser(userData.user);
setShowLoginDialog(false);
// Get role label
let roleLabel = '';
if (userData.user.role_user === 'ketuajurusan') {
roleLabel = 'Ketua Jurusan';
} else if (userData.user.role_user === 'ketuaprodi') {
roleLabel = 'Ketua Prodi';
} else if (userData.user.role_user === 'admin') {
roleLabel = 'Admin';
}
showSuccess("Berhasil!", `Selamat datang, ${roleLabel}`);
// Redirect based on user role
if (userData.user.role_user === 'ketuajurusan' || userData.user.role_user === 'ketuaprodi') {
router.push('/dashboard');
} else if (userData.user.role_user === 'admin') {
router.push('/keloladata/mahasiswa');
}
};
if (isLoading) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto mb-4"></div>
<p className="text-muted-foreground">Memuat...</p>
</div>
</div>
);
}
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-900 via-blue-900 to-slate-800 relative overflow-hidden">
{/* Background decorative elements */}
<div className="absolute inset-0 overflow-hidden">
<div className="absolute -top-40 -right-40 w-80 h-80 bg-blue-500/10 rounded-full blur-3xl"></div>
<div className="absolute -bottom-40 -left-40 w-80 h-80 bg-purple-500/10 rounded-full blur-3xl"></div>
</div>
<div className="w-full max-w-sm mx-auto p-4 relative z-10">
{/* Header */}
<div className="text-center space-y-3 mb-6">
<h1 className="text-2xl md:text-2xl lg:text-3xl font-bold gradient-text-animated leading-tight">
Portal Data Informatika
</h1>
</div>
{showLoginDialog && (
<AutoLoginDialog onLoginSuccess={handleLoginSuccess} />
)}
</div>
</div>
);
}
// Auto-opening login dialog component
interface AutoLoginDialogProps {
onLoginSuccess: (userData: any) => void;
}
function AutoLoginDialog({ onLoginSuccess }: AutoLoginDialogProps) {
const { showSuccess, showError } = useToast();
const [isLoading, setIsLoading] = useState(false);
const [activeTab, setActiveTab] = useState("ketua");
// Ketua Jurusan form state
const [ketuaForm, setKetuaForm] = useState({
nip: "",
password: "",
});
// Admin form state
const [adminForm, setAdminForm] = useState({
username: "",
password: "",
});
const handleKetuaLogin = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
try {
const response = await fetch("/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
nip: ketuaForm.nip,
password: ketuaForm.password,
role: "pimpinan", // Will accept both ketuajurusan and ketuaprodi
}),
});
const data = await response.json();
if (response.ok) {
onLoginSuccess(data);
setKetuaForm({ nip: "", password: "" });
} else {
showError("Gagal!", data.message || "NIP atau password salah");
}
} catch (error) {
showError("Gagal!", "Terjadi kesalahan saat login");
} finally {
setIsLoading(false);
}
};
const handleAdminLogin = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
try {
const response = await fetch("/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: adminForm.username,
password: adminForm.password,
role: "admin",
}),
});
const data = await response.json();
if (response.ok) {
onLoginSuccess(data);
setAdminForm({ username: "", password: "" });
} else {
showError("Gagal!", data.message || "Username atau password salah");
}
} catch (error) {
showError("Gagal!", "Terjadi kesalahan saat login");
} finally {
setIsLoading(false);
}
};
return (
<div className="glass-effect rounded-2xl shadow-2xl p-6 w-full relative overflow-hidden">
<div className="relative z-10">
<div className="text-center mb-6">
<h2 className="text-xl font-bold text-white mb-1">
Login ke PODIF
</h2>
<p className="text-slate-300 text-sm">
Silakan login untuk melanjutkan
</p>
</div>
<div className="space-y-4">
{/* Tab buttons with glass effect */}
<div className="flex rounded-xl glass-tab p-1">
<button
onClick={() => setActiveTab("ketua")}
className={`flex-1 py-2 px-3 rounded-md text-sm font-semibold transition-all duration-200 ${
activeTab === "ketua"
? "glass-tab-active text-white"
: "text-slate-300 hover:text-white hover:bg-white/5"
}`}
>
Pimpinan
</button>
<button
onClick={() => setActiveTab("admin")}
className={`flex-1 py-2 px-3 rounded-md text-sm font-semibold transition-all duration-200 ${
activeTab === "admin"
? "glass-tab-active text-white"
: "text-slate-300 hover:text-white hover:bg-white/5"
}`}
>
Admin
</button>
</div>
{/* Pimpinan form (Ketua Jurusan / Ketua Prodi) */}
{activeTab === "ketua" && (
<form onSubmit={handleKetuaLogin} className="space-y-4">
<div className="space-y-1">
<label htmlFor="nip" className="block text-sm font-medium text-white/90">
NIP
</label>
<input
id="nip"
type="text"
placeholder="Masukkan NIP"
value={ketuaForm.nip}
onChange={(e) => setKetuaForm({ ...ketuaForm, nip: e.target.value })}
required
className="glass-input w-full px-3 py-2 rounded-lg text-white placeholder-slate-400 focus:outline-none"
/>
</div>
<div className="space-y-1">
<label htmlFor="ketua-password" className="block text-sm font-medium text-white/90">
Password
</label>
<input
id="ketua-password"
type="password"
placeholder="Masukkan password"
value={ketuaForm.password}
onChange={(e) => setKetuaForm({ ...ketuaForm, password: e.target.value })}
required
className="glass-input w-full px-3 py-2 rounded-lg text-white placeholder-slate-400 focus:outline-none"
/>
</div>
<button
type="submit"
disabled={isLoading}
className="glass-button w-full text-white font-medium py-2.5 px-4 rounded-lg"
>
{isLoading ? (
<div className="flex items-center justify-center">
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
Loading...
</div>
) : (
"Login sebagai Pimpinan"
)}
</button>
</form>
)}
{/* Admin form */}
{activeTab === "admin" && (
<form onSubmit={handleAdminLogin} className="space-y-4">
<div className="space-y-1">
<label htmlFor="username" className="block text-sm font-medium text-white/90">
Username
</label>
<input
id="username"
type="text"
placeholder="Masukkan username"
value={adminForm.username}
onChange={(e) => setAdminForm({ ...adminForm, username: e.target.value })}
required
className="glass-input w-full px-3 py-2 rounded-lg text-white placeholder-slate-400 focus:outline-none"
/>
</div>
<div className="space-y-1">
<label htmlFor="admin-password" className="block text-sm font-medium text-white/90">
Password
</label>
<input
id="admin-password"
type="password"
placeholder="Masukkan password"
value={adminForm.password}
onChange={(e) => setAdminForm({ ...adminForm, password: e.target.value })}
required
className="glass-input w-full px-3 py-2 rounded-lg text-white placeholder-slate-400 focus:outline-none"
/>
</div>
<button
type="submit"
disabled={isLoading}
className="glass-button w-full text-white font-medium py-2.5 px-4 rounded-lg"
>
{isLoading ? (
<div className="flex items-center justify-center">
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
Loading...
</div>
) : (
"Login sebagai Admin"
)}
</button>
</form>
)}
</div>
</div>
</div>
);
}