forked from baron/baron-sso
인증 상태에 따른 레이아웃 및 UI 개선
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
import { BadgeCheck, Moon, ShieldHalf, Sun } from "lucide-react";
|
||||
import { BadgeCheck, LogOut, Moon, ShieldHalf, Sun, User } from "lucide-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useAuth } from "react-oidc-context";
|
||||
import { NavLink, Outlet } from "react-router-dom";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { t } from "../../lib/i18n";
|
||||
import { Toaster } from "../ui/toaster";
|
||||
import { fetchMe } from "../../features/auth/authApi";
|
||||
|
||||
const navItems = [
|
||||
{
|
||||
@@ -14,10 +17,17 @@ const navItems = [
|
||||
];
|
||||
|
||||
function AppLayout() {
|
||||
const [theme, setTheme] = useState<"light" | "dark">(() => {
|
||||
const stored = window.localStorage.getItem("admin_theme");
|
||||
return stored === "dark" ? "dark" : "light";
|
||||
});
|
||||
const auth = useAuth();
|
||||
const { data: profile } = useQuery({
|
||||
queryKey: ["me"],
|
||||
queryFn: fetchMe,
|
||||
enabled: auth.isAuthenticated,
|
||||
});
|
||||
|
||||
const [theme, setTheme] = useState<"light" | "dark">(() => {
|
||||
const stored = window.localStorage.getItem("admin_theme");
|
||||
return stored === "dark" ? "dark" : "light";
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
@@ -30,9 +40,20 @@ function AppLayout() {
|
||||
window.localStorage.setItem("admin_theme", theme);
|
||||
}, [theme]);
|
||||
|
||||
const toggleTheme = () => {
|
||||
setTheme((prev) => (prev === "light" ? "dark" : "light"));
|
||||
};
|
||||
const toggleTheme = () => {
|
||||
setTheme((prev) => (prev === "light" ? "dark" : "light"));
|
||||
};
|
||||
|
||||
const handleLogout = () => {
|
||||
auth.signoutRedirect();
|
||||
};
|
||||
|
||||
// Set initial tenant ID if profile is loaded and no tenant is selected
|
||||
useEffect(() => {
|
||||
if (profile?.tenantId && !window.localStorage.getItem("dev_tenant_id")) {
|
||||
window.localStorage.setItem("dev_tenant_id", profile.tenantId);
|
||||
}
|
||||
}, [profile]);
|
||||
|
||||
return (
|
||||
<div className="grid min-h-screen bg-background text-foreground md:grid-cols-[240px,1fr]">
|
||||
@@ -61,6 +82,11 @@ function AppLayout() {
|
||||
<span className="rounded-full border border-border px-3 py-1">
|
||||
{t("ui.dev.env_badge", "Env: dev")}
|
||||
</span>
|
||||
{profile?.tenant && (
|
||||
<span className="rounded-full bg-primary/10 px-3 py-1 text-primary border border-primary/20">
|
||||
Tenant: {profile.tenant.name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
{navItems.map(({ labelKey, labelFallback, to, icon: Icon }) => (
|
||||
@@ -116,6 +142,16 @@ function AppLayout() {
|
||||
? t("ui.common.theme_light", "Light")
|
||||
: t("ui.common.theme_dark", "Dark")}
|
||||
</button>
|
||||
{auth.isAuthenticated && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleLogout}
|
||||
className="inline-flex items-center gap-2 rounded-full border border-destructive/20 bg-destructive/5 px-3 py-2 text-destructive transition hover:bg-destructive/10"
|
||||
>
|
||||
<LogOut size={16} />
|
||||
Logout
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { AlertCircle, CheckCircle2, Info } from "lucide-react";
|
||||
import { CheckCircle2, AlertCircle, Info } from "lucide-react";
|
||||
|
||||
import { cn } from "../../lib/utils";
|
||||
import { useToastState } from "./use-toast";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user