You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

155 lines
5.5 KiB

import { useState } from 'react'
import { Navigate, useLocation } from 'react-router-dom'
import type { Location } from 'react-router-dom'
import { Ic, Pattern } from '@/icons'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { useAuth, useLoginMutation } from '@/features/auth/use-auth'
import { ApiError } from '@/services/http'
import { siteConfig } from '@/config/site'
import { AqilaLogo } from '@/components/AqilaLogo'
function Field({ label, children }: { label: string; children: React.ReactNode }) {
return (
<div className="space-y-1.5">
<p className="text-xs font-semibold text-grey-2">{label}</p>
{children}
</div>
)
}
export default function LoginPage() {
const location = useLocation()
const { isAuthenticated } = useAuth()
const loginMutation = useLoginMutation()
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [showPassword, setShowPassword] = useState(false)
const from = (location.state as { from?: Location } | null)?.from?.pathname ?? '/'
if (isAuthenticated) {
return <Navigate to={from} replace />
}
const valid = email.trim().length > 0 && password.length > 0
const submit = (e: React.FormEvent) => {
e.preventDefault()
if (!valid || loginMutation.isPending) return
loginMutation.mutate({ email: email.trim(), password })
}
const fillDemo = () => {
setEmail('admin@gmail.com')
setPassword('admin')
}
const errorMessage =
loginMutation.error instanceof ApiError
? loginMutation.error.message
: loginMutation.error
? 'ورود ناموفق بود. دوباره تلاش کنید.'
: null
return (
<div className="relative flex min-h-svh items-center justify-center overflow-hidden bg-background px-4">
<div className="pointer-events-none absolute inset-0 opacity-[0.04]">
<Pattern />
</div>
<div className="relative w-full max-w-[420px]">
{/* لوگو و نام برند */}
<div className="mb-6 flex flex-col items-center gap-2.5 text-center">
<div className="flex size-14 items-center justify-center rounded-2xl bg-primary text-white shadow-lg">
<AqilaLogo className="size-8 text-white" />
</div>
<div>
<h1 className="text-xl font-black text-foreground">{siteConfig.name}</h1>
<p className="text-xs text-grey-3 mt-1">ورود به پنل مدیریت و داشبورد</p>
</div>
</div>
{/* کارت لاگین */}
<form
onSubmit={submit}
className="space-y-4 rounded-2xl border border-border-soft bg-card/60 p-6 shadow-2xl backdrop-blur"
>
{/* راهنمای لاگین دمو */}
<div className="flex items-center justify-between rounded-xl border border-primary/20 bg-primary/10 p-3 text-xs">
<div>
<span className="font-bold text-primary block">حساب آزمایشی آماده:</span>
<span dir="ltr" className="text-[11px] text-grey-2 font-mono">admin@gmail.com / admin</span>
</div>
<Button
type="button"
variant="outline"
size="sm"
onClick={fillDemo}
className="h-7 text-[11px]"
>
پر کردن خودکار
</Button>
</div>
<Field label="ایمیل حساب کاربری">
<Input
type="email"
dir="ltr"
className="text-left"
autoComplete="username"
placeholder="you@example.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
autoFocus
/>
</Field>
<Field label="رمز عبور">
<div className="relative">
<Input
type={showPassword ? 'text' : 'password'}
dir="ltr"
className="text-left pe-11"
autoComplete="current-password"
placeholder="••••••••"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button
type="button"
onClick={() => setShowPassword((v) => !v)}
className="absolute inset-y-0 start-0 flex w-11 items-center justify-center text-grey-3 transition-colors hover:text-grey-1 [&_svg]:size-4"
aria-label={showPassword ? 'مخفی‌کردن رمز' : 'نمایش رمز'}
tabIndex={-1}
>
<Ic name={showPassword ? 'eyeOff' : 'eye'} />
</button>
</div>
</Field>
{errorMessage && (
<div className="flex items-start gap-2 rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-rose-400">
<Ic name="alert" className="size-4 shrink-0 mt-0.5" />
<span>{errorMessage}</span>
</div>
)}
<Button
type="submit"
size="lg"
className="w-full"
disabled={!valid || loginMutation.isPending}
>
{loginMutation.isPending ? 'در حال ورود…' : 'ورود به حساب کاربری'}
</Button>
</form>
<p className="mt-4 text-center text-xs text-grey-4">
پشتیبانی از قالبهای سفارشی و اتصال مستقیم به API
</p>
</div>
</div>
)
}