334 lines
11 KiB
TypeScript
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>
|
|
);
|
|
}
|