107 lines
4.3 KiB
TypeScript
107 lines
4.3 KiB
TypeScript
import { useState } from 'react';
|
|||
|
|
import { Link, Outlet, useNavigate } from 'react-router-dom';
|
||
|
|
import { LogOut, Moon, Sun } from 'lucide-react';
|
||
|
|
import { useAuth } from '@/hooks/useAuth';
|
||
|
|
import { useTheme } from '@/hooks/useTheme';
|
||
|
|
import { APP_NAME } from '@/utils/constants';
|
||
|
|
import { cn } from '@/lib/utils';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Full-viewport admin shell — not the mobile PWA frame.
|
||
|
|
* Journey AppHeader / app-mobile-shell are intentionally absent.
|
||
|
|
*/
|
||
|
|
export function AdminLayout() {
|
||
|
|
const { user, signOut } = useAuth();
|
||
|
|
const { toggleTheme, isDark } = useTheme();
|
||
|
|
const navigate = useNavigate();
|
||
|
|
const [confirmLogout, setConfirmLogout] = useState(false);
|
||
|
|
|
||
|
|
const handleSignOut = async () => {
|
||
|
|
await signOut();
|
||
|
|
setConfirmLogout(false);
|
||
|
|
navigate('/login', { replace: true });
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="admin-app-shell flex h-dvh min-h-0 flex-col bg-slate-100 text-slate-900 dark:bg-slate-950 dark:text-slate-50">
|
||
|
|
<header className="shrink-0 border-b border-slate-200 bg-white dark:border-slate-800 dark:bg-slate-900">
|
||
|
|
<div className="mx-auto flex h-14 w-full max-w-6xl items-center justify-between gap-3 px-4">
|
||
|
|
<div className="min-w-0">
|
||
|
|
<p className="truncate text-sm font-semibold tracking-tight">
|
||
|
|
{APP_NAME}
|
||
|
|
<span className="mx-2 text-slate-300 dark:text-slate-600">|</span>
|
||
|
|
<span className="text-slate-600 dark:text-slate-300">پنل ادمین</span>
|
||
|
|
</p>
|
||
|
|
{user?.email ? (
|
||
|
|
<p className="truncate text-[11px] text-slate-500" dir="ltr">
|
||
|
|
{user.email}
|
||
|
|
</p>
|
||
|
|
) : null}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex shrink-0 items-center gap-2">
|
||
|
|
<Link
|
||
|
|
to="/"
|
||
|
|
className={cn(
|
||
|
|
'rounded-lg border border-slate-200 px-3 py-1.5 text-xs text-slate-700',
|
||
|
|
'hover:bg-slate-50 dark:border-slate-600 dark:text-slate-200 dark:hover:bg-slate-800',
|
||
|
|
'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2',
|
||
|
|
)}
|
||
|
|
>
|
||
|
|
بازگشت به اپ
|
||
|
|
</Link>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={toggleTheme}
|
||
|
|
className="inline-flex h-9 w-9 items-center justify-center rounded-lg border border-slate-200 text-slate-600 dark:border-slate-600 dark:text-slate-300"
|
||
|
|
aria-label={isDark ? 'حالت روشن' : 'حالت تاریک'}
|
||
|
|
>
|
||
|
|
{isDark ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={() => setConfirmLogout(true)}
|
||
|
|
className="inline-flex h-9 items-center gap-1.5 rounded-lg border border-slate-200 px-3 text-xs text-slate-700 dark:border-slate-600 dark:text-slate-200"
|
||
|
|
aria-label="خروج از حساب"
|
||
|
|
>
|
||
|
|
<LogOut className="h-3.5 w-3.5" />
|
||
|
|
خروج
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</header>
|
||
|
|
|
||
|
|
<main className="min-h-0 flex-1 overflow-hidden">
|
||
|
|
<Outlet />
|
||
|
|
</main>
|
||
|
|
|
||
|
|
{confirmLogout ? (
|
||
|
|
<div className="fixed inset-0 z-[60] flex items-end justify-center bg-slate-900/40 p-4 sm:items-center">
|
||
|
|
<div className="w-full max-w-sm space-y-4 rounded-xl border border-slate-200 bg-white p-5 shadow-lg dark:border-slate-700 dark:bg-slate-900">
|
||
|
|
<h2 className="text-base font-semibold">خروج از پنل ادمین</h2>
|
||
|
|
<p className="text-sm text-slate-600 dark:text-slate-300">
|
||
|
|
از حساب کاربری خارج میشوید؟
|
||
|
|
</p>
|
||
|
|
<div className="flex gap-2">
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={() => setConfirmLogout(false)}
|
||
|
|
className="flex-1 rounded-lg border border-slate-200 px-3 py-2 text-sm dark:border-slate-600"
|
||
|
|
>
|
||
|
|
انصراف
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
type="button"
|
||
|
|
onClick={() => void handleSignOut()}
|
||
|
|
className="flex-1 rounded-lg bg-slate-900 px-3 py-2 text-sm text-white dark:bg-slate-100 dark:text-slate-900"
|
||
|
|
>
|
||
|
|
خروج
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
) : null}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|