chore: merge admin repo history into monorepo at admin/

git-subtree-dir: admin
git-subtree-mainline: 35f5084005
git-subtree-split: 9f1eccd2f7
This commit is contained in:
2026-09-27 10:30:47 +03:30
49 changed files with 11446 additions and 0 deletions
+78
View File
@@ -0,0 +1,78 @@
"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>
);
}