Files
portaldata/app/page.tsx
2025-06-29 10:30:14 +07:00

391 lines
14 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Loader2, Eye, EyeOff } from "lucide-react";
import { ThemeProvider } from '@/components/theme-provider';
import { Toaster } from '@/components/ui/toaster';
export default function LandingPage() {
const router = useRouter();
const [isLoginOpen, setIsLoginOpen] = useState(true);
const [isRegisterOpen, setIsRegisterOpen] = useState(false);
const [activeTab, setActiveTab] = useState('dosen');
const [loading, setLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const [error, setError] = useState('');
// Admin form state
const [adminForm, setAdminForm] = useState({
username: '',
password: ''
});
// Dosen form state
const [dosenForm, setDosenForm] = useState({
nip: '',
password: ''
});
// Register form state
const [registerForm, setRegisterForm] = useState({
nip: '',
password: '',
confirmPassword: ''
});
const handleAdminLogin = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError('');
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) {
setIsLoginOpen(false);
router.push('/dashboard');
} else {
setError(data.error || 'Login gagal');
}
} catch (err) {
setError('Terjadi kesalahan saat login');
} finally {
setLoading(false);
}
};
const handleDosenLogin = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError('');
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
nip: dosenForm.nip,
password: dosenForm.password,
role: 'dosen'
}),
});
const data = await response.json();
if (response.ok) {
setIsLoginOpen(false);
router.push('/dashboard');
} else {
setError(data.error || 'Login gagal');
}
} catch (err) {
setError('Terjadi kesalahan saat login');
} finally {
setLoading(false);
}
};
const handleRegister = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError('');
if (registerForm.password !== registerForm.confirmPassword) {
setError('Password dan konfirmasi password tidak cocok');
setLoading(false);
return;
}
try {
const response = await fetch('/api/auth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
nip: registerForm.nip,
password: registerForm.password
}),
});
const data = await response.json();
if (response.ok) {
setIsRegisterOpen(false);
setIsLoginOpen(true);
setActiveTab('dosen');
setError('');
} else {
setError(data.error || 'Registrasi gagal');
}
} catch (err) {
setError('Terjadi kesalahan saat registrasi');
} finally {
setLoading(false);
}
};
const openRegister = () => {
setIsLoginOpen(false);
setIsRegisterOpen(true);
};
const openLogin = () => {
setIsRegisterOpen(false);
setIsLoginOpen(true);
};
return (
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-100 dark:from-gray-900 dark:to-gray-800">
{/* Login Dialog */}
<Dialog open={isLoginOpen} onOpenChange={() => {}}>
<DialogContent className="sm:max-w-md" hideClose>
<DialogHeader>
<DialogTitle>Login Portal Data Informatika</DialogTitle>
<DialogDescription>
Silakan login sesuai dengan role Anda
</DialogDescription>
</DialogHeader>
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="dosen">Dosen</TabsTrigger>
<TabsTrigger value="admin">Admin</TabsTrigger>
</TabsList>
<TabsContent value="dosen" className="space-y-4">
<form onSubmit={handleDosenLogin} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="nip">NIP</Label>
<Input
id="nip"
type="text"
placeholder="Masukkan NIP"
value={dosenForm.nip}
onChange={(e) => setDosenForm({ ...dosenForm, nip: e.target.value })}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="dosen-password">Password</Label>
<div className="relative">
<Input
id="dosen-password"
type={showPassword ? "text" : "password"}
placeholder="Masukkan password"
value={dosenForm.password}
onChange={(e) => setDosenForm({ ...dosenForm, password: e.target.value })}
required
/>
<Button
type="button"
variant="ghost"
size="sm"
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? (
<EyeOff className="h-4 w-4" />
) : (
<Eye className="h-4 w-4" />
)}
</Button>
</div>
</div>
<Button type="submit" className="w-full" disabled={loading}>
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Login sebagai Dosen
</Button>
</form>
<div className="text-center pt-4 border-t">
<p className="text-sm text-gray-600 dark:text-gray-400 inline">
Belum punya akun?{' '}
</p>
<Button
type="button"
variant="link"
className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 p-0 h-auto inline"
onClick={openRegister}
>
Daftar disini
</Button>
</div>
</TabsContent>
<TabsContent value="admin" className="space-y-4">
<form onSubmit={handleAdminLogin} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="username">Username</Label>
<Input
id="username"
type="text"
placeholder="Masukkan username"
value={adminForm.username}
onChange={(e) => setAdminForm({ ...adminForm, username: e.target.value })}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="admin-password">Password</Label>
<div className="relative">
<Input
id="admin-password"
type={showPassword ? "text" : "password"}
placeholder="Masukkan password"
value={adminForm.password}
onChange={(e) => setAdminForm({ ...adminForm, password: e.target.value })}
required
/>
<Button
type="button"
variant="ghost"
size="sm"
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? (
<EyeOff className="h-4 w-4" />
) : (
<Eye className="h-4 w-4" />
)}
</Button>
</div>
</div>
<Button type="submit" className="w-full" disabled={loading}>
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Login sebagai Admin
</Button>
</form>
</TabsContent>
</Tabs>
{error && (
<Alert className="mt-4">
<AlertDescription className="text-red-600">
{error}
</AlertDescription>
</Alert>
)}
</DialogContent>
</Dialog>
{/* Register Dialog */}
<Dialog open={isRegisterOpen} onOpenChange={() => {}}>
<DialogContent className="sm:max-w-md" hideClose>
<DialogHeader>
<DialogTitle>Registrasi Dosen</DialogTitle>
<DialogDescription>
Daftar akun baru untuk dosen Portal Data Informatika
</DialogDescription>
</DialogHeader>
<form onSubmit={handleRegister} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="register-nip">NIP</Label>
<Input
id="register-nip"
type="text"
placeholder="Masukkan NIP"
value={registerForm.nip}
onChange={(e) => setRegisterForm({ ...registerForm, nip: e.target.value })}
required
/>
</div>
<div className="space-y-2">
<Label htmlFor="register-password">Password</Label>
<div className="relative">
<Input
id="register-password"
type={showPassword ? "text" : "password"}
placeholder="Masukkan password (min. 6 karakter)"
value={registerForm.password}
onChange={(e) => setRegisterForm({ ...registerForm, password: e.target.value })}
required
/>
<Button
type="button"
variant="ghost"
size="sm"
className="absolute right-0 top-0 h-full px-3 py-2 hover:bg-transparent"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? (
<EyeOff className="h-4 w-4" />
) : (
<Eye className="h-4 w-4" />
)}
</Button>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="confirm-password">Konfirmasi Password</Label>
<Input
id="confirm-password"
type="password"
placeholder="Konfirmasi password"
value={registerForm.confirmPassword}
onChange={(e) => setRegisterForm({ ...registerForm, confirmPassword: e.target.value })}
required
/>
</div>
<Button type="submit" className="w-full" disabled={loading}>
{loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
Daftar sebagai Dosen
</Button>
</form>
<div className="text-center pt-4 border-t">
<p className="text-sm text-gray-600 dark:text-gray-400 inline">
Sudah punya akun?{' '}
</p>
<Button
type="button"
variant="link"
className="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300 p-0 h-auto inline"
onClick={openLogin}
>
Login
</Button>
</div>
{error && (
<Alert className="mt-4">
<AlertDescription className="text-red-600">
{error}
</AlertDescription>
</Alert>
)}
</DialogContent>
</Dialog>
</div>
<Toaster />
</ThemeProvider>
);
}