- Update all environment files to use new PostgreSQL API endpoint - Fix CORS configuration in API server - Import 35 filaments and 29 colors from PDF data - Fix TypeScript type error in dashboard - Add back emoji icons for dark mode toggle - Remove debugging code and test buttons - Clean up error handling
106 lines
4.1 KiB
TypeScript
106 lines
4.1 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { authService } from '@/src/services/api';
|
|
|
|
export default function AdminLogin() {
|
|
const router = useRouter();
|
|
const [username, setUsername] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [error, setError] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
// Set dark mode by default
|
|
useEffect(() => {
|
|
document.documentElement.classList.add('dark');
|
|
}, []);
|
|
|
|
const handleLogin = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
setError('');
|
|
setLoading(true);
|
|
|
|
try {
|
|
const response = await authService.login(username, password);
|
|
|
|
// Store token in localStorage
|
|
localStorage.setItem('authToken', response.token);
|
|
localStorage.setItem('tokenExpiry', String(Date.now() + 24 * 60 * 60 * 1000)); // 24 hours
|
|
|
|
// Redirect to admin dashboard
|
|
router.push('/upadaj/dashboard');
|
|
} catch (err: any) {
|
|
setError('Neispravno korisničko ime ili lozinka');
|
|
console.error('Login error:', err);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900 py-12 px-4 sm:px-6 lg:px-8">
|
|
<div className="max-w-md w-full space-y-8">
|
|
<div>
|
|
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900 dark:text-white">
|
|
Admin Prijava
|
|
</h2>
|
|
<p className="mt-2 text-center text-sm text-gray-600 dark:text-gray-400">
|
|
Prijavite se za upravljanje filamentima
|
|
</p>
|
|
</div>
|
|
<form className="mt-8 space-y-6" onSubmit={handleLogin}>
|
|
{error && (
|
|
<div className="rounded-md bg-red-50 dark:bg-red-900/20 p-4">
|
|
<p className="text-sm text-red-800 dark:text-red-400">{error}</p>
|
|
</div>
|
|
)}
|
|
<div className="rounded-md shadow-sm -space-y-px">
|
|
<div>
|
|
<label htmlFor="username" className="sr-only">
|
|
Korisničko ime
|
|
</label>
|
|
<input
|
|
id="username"
|
|
name="username"
|
|
type="text"
|
|
autoComplete="username"
|
|
required
|
|
className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 dark:border-gray-700 placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white rounded-t-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm dark:bg-gray-800"
|
|
placeholder="Korisničko ime"
|
|
value={username}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label htmlFor="password" className="sr-only">
|
|
Lozinka
|
|
</label>
|
|
<input
|
|
id="password"
|
|
name="password"
|
|
type="password"
|
|
autoComplete="current-password"
|
|
required
|
|
className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 dark:border-gray-700 placeholder-gray-500 dark:placeholder-gray-400 text-gray-900 dark:text-white rounded-b-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm dark:bg-gray-800"
|
|
placeholder="Lozinka"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<button
|
|
type="submit"
|
|
disabled={loading}
|
|
className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
{loading ? 'Prijavljivanje...' : 'Prijavite se'}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |