first commit
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
'use client';
|
||||
|
||||
import { Suspense, useState } from 'react';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
|
||||
function LoginInner() {
|
||||
const router = useRouter();
|
||||
const params = useSearchParams();
|
||||
const from = params.get('from') || '/admin';
|
||||
const [password, setPassword] = useState('');
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
|
||||
async function submit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
setBusy(true);
|
||||
setError(null);
|
||||
try {
|
||||
const res = await fetch('/api/admin/login', {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ password }),
|
||||
});
|
||||
if (res.ok) {
|
||||
router.replace(from);
|
||||
router.refresh();
|
||||
} else {
|
||||
setError('Incorrect password.');
|
||||
setBusy(false);
|
||||
}
|
||||
} catch {
|
||||
setError('Something went wrong. Try again.');
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div dir="ltr" className="flex min-h-screen items-center justify-center px-5">
|
||||
<div
|
||||
aria-hidden
|
||||
className="pointer-events-none fixed inset-0 -z-10 bg-radial-aurora opacity-50"
|
||||
/>
|
||||
<form
|
||||
onSubmit={submit}
|
||||
className="w-full max-w-sm rounded-2xl border border-white/10 bg-base-900/70 p-8 backdrop-blur-xl"
|
||||
>
|
||||
<div className="mb-6 flex items-center gap-3">
|
||||
<span className="grid h-10 w-10 place-items-center rounded-xl bg-electric/15 font-mono text-sm font-bold text-electric">
|
||||
SA
|
||||
</span>
|
||||
<div>
|
||||
<h1 className="text-base font-semibold text-white">Content CMS</h1>
|
||||
<p className="font-mono text-[0.65rem] uppercase tracking-wider text-slate-500">
|
||||
soroushasadi.ir
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label className="mb-1.5 block font-mono text-[0.68rem] uppercase tracking-wider text-slate-400">
|
||||
Admin password
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
autoFocus
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="w-full rounded-lg border border-white/10 bg-base-900/60 px-3 py-2.5 text-sm text-slate-100 outline-none focus:border-electric/60"
|
||||
placeholder="••••••••"
|
||||
/>
|
||||
|
||||
{error && <p className="mt-3 text-sm text-magenta">{error}</p>}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={busy || !password}
|
||||
className="mt-5 w-full rounded-lg bg-electric px-4 py-2.5 text-sm font-semibold text-base-900 transition-opacity hover:opacity-90 disabled:opacity-50"
|
||||
>
|
||||
{busy ? 'Signing in…' : 'Sign in'}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function AdminLoginPage() {
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<LoginInner />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user