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>
|
|||
|
|
);
|
|||
|
|
}
|