92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
'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>
|
|
);
|
|
}
|