75a0ba593d
git-subtree-dir: admin git-subtree-mainline:35f5084005git-subtree-split:9f1eccd2f7
79 lines
2.6 KiB
TypeScript
79 lines
2.6 KiB
TypeScript
"use client";
|
||
|
||
import { useState, useEffect } from "react";
|
||
import { useRouter } from "next/navigation";
|
||
import { ShieldCheck } from "lucide-react";
|
||
import { Button } from "@/components/ui/Button";
|
||
import { TextField } from "@/components/ui/TextField";
|
||
import { ErrorBanner } from "@/components/ui/ErrorBanner";
|
||
import { Card } from "@/components/ui/Card";
|
||
import { requestOtp } from "@/lib/api";
|
||
import { formatApiError } from "@/lib/hooks";
|
||
import { useAuth } from "@/lib/auth-context";
|
||
|
||
const PHONE_REGEX = /^09\d{9}$/;
|
||
|
||
export default function LoginPage() {
|
||
const router = useRouter();
|
||
const { status } = useAuth();
|
||
const [phone, setPhone] = useState("");
|
||
const [loading, setLoading] = useState(false);
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
useEffect(() => {
|
||
if (status === "authenticated") router.replace("/");
|
||
}, [status, router]);
|
||
|
||
const isValid = PHONE_REGEX.test(phone);
|
||
|
||
async function handleSubmit() {
|
||
if (!isValid) return;
|
||
setLoading(true);
|
||
setError(null);
|
||
try {
|
||
await requestOtp(phone);
|
||
router.push(`/verify?phone=${phone}`);
|
||
} catch (err) {
|
||
setError(formatApiError(err));
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
|
||
return (
|
||
<div className="min-h-dvh flex items-center justify-center px-4">
|
||
<Card className="w-full max-w-sm flex flex-col items-center gap-6 !p-8">
|
||
<div className="w-16 h-16 rounded-(--radius-lg) bg-(--color-brand-500) flex items-center justify-center shadow-(--shadow-cute-md)">
|
||
<ShieldCheck size={28} className="text-white" />
|
||
</div>
|
||
<div className="text-center">
|
||
<h1 className="font-[var(--font-display)] font-extrabold text-[22px]">
|
||
پنل ادمین دلدل
|
||
</h1>
|
||
<p className="text-[13px] text-(--color-content-secondary) mt-1">
|
||
فقط برای مدیران سیستم
|
||
</p>
|
||
</div>
|
||
|
||
<div className="w-full flex flex-col gap-4">
|
||
<TextField
|
||
label="شماره موبایل ادمین"
|
||
type="tel"
|
||
inputMode="numeric"
|
||
placeholder="09xxxxxxxxx"
|
||
dir="ltr"
|
||
className="text-center tracking-widest"
|
||
value={phone}
|
||
onChange={(e) => setPhone(e.target.value.replace(/\D/g, "").slice(0, 11))}
|
||
onKeyDown={(e) => e.key === "Enter" && handleSubmit()}
|
||
/>
|
||
<ErrorBanner message={error} />
|
||
<Button size="lg" isBlock disabled={!isValid} isLoading={loading} onClick={handleSubmit}>
|
||
دریافت کد تایید
|
||
</Button>
|
||
</div>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|