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 { useEffect, useState } from "react";
|
||||||
|
import { useAuth } from "react-oidc-context";
|
||||||
import { NavLink, Outlet } from "react-router-dom";
|
import { NavLink, Outlet } from "react-router-dom";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { t } from "../../lib/i18n";
|
import { t } from "../../lib/i18n";
|
||||||
import { Toaster } from "../ui/toaster";
|
import { Toaster } from "../ui/toaster";
|
||||||
|
import { fetchMe } from "../../features/auth/authApi";
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{
|
{
|
||||||
@@ -14,10 +17,17 @@ const navItems = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
function AppLayout() {
|
function AppLayout() {
|
||||||
const [theme, setTheme] = useState<"light" | "dark">(() => {
|
const auth = useAuth();
|
||||||
const stored = window.localStorage.getItem("admin_theme");
|
const { data: profile } = useQuery({
|
||||||
return stored === "dark" ? "dark" : "light";
|
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(() => {
|
useEffect(() => {
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
@@ -30,9 +40,20 @@ function AppLayout() {
|
|||||||
window.localStorage.setItem("admin_theme", theme);
|
window.localStorage.setItem("admin_theme", theme);
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
const toggleTheme = () => {
|
const toggleTheme = () => {
|
||||||
setTheme((prev) => (prev === "light" ? "dark" : "light"));
|
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 (
|
return (
|
||||||
<div className="grid min-h-screen bg-background text-foreground md:grid-cols-[240px,1fr]">
|
<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">
|
<span className="rounded-full border border-border px-3 py-1">
|
||||||
{t("ui.dev.env_badge", "Env: dev")}
|
{t("ui.dev.env_badge", "Env: dev")}
|
||||||
</span>
|
</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>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
{navItems.map(({ labelKey, labelFallback, to, icon: Icon }) => (
|
{navItems.map(({ labelKey, labelFallback, to, icon: Icon }) => (
|
||||||
@@ -116,6 +142,16 @@ function AppLayout() {
|
|||||||
? t("ui.common.theme_light", "Light")
|
? t("ui.common.theme_light", "Light")
|
||||||
: t("ui.common.theme_dark", "Dark")}
|
: t("ui.common.theme_dark", "Dark")}
|
||||||
</button>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</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 { cn } from "../../lib/utils";
|
||||||
import { useToastState } from "./use-toast";
|
import { useToastState } from "./use-toast";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user