live action
This commit is contained in:
98
frontend/src/components/DashboardLayout.tsx
Normal file
98
frontend/src/components/DashboardLayout.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { NavLink, Outlet, useNavigate } from "react-router-dom";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faHouse, faBriefcase, faArrowRightFromBracket, faUser } from "@fortawesome/free-solid-svg-icons";
|
||||
import { Button } from "./ui/button";
|
||||
import { ThemeToggle } from "./ThemeToggle";
|
||||
import { useAuth } from "../providers/auth-provider";
|
||||
import { cn } from "../lib/utils";
|
||||
import { apiClient } from "../api/client";
|
||||
|
||||
export function DashboardLayout() {
|
||||
const { user, token, logout } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
||||
|
||||
const navigation = useMemo(
|
||||
() => [
|
||||
{ label: "Home", to: "/home", icon: faHouse },
|
||||
{ label: "Jobs", to: "/jobs", icon: faBriefcase }
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const socketUrl = useMemo(() => apiClient.defaults.baseURL || window.location.origin, []);
|
||||
|
||||
const handleLogout = () => {
|
||||
setIsLoggingOut(true);
|
||||
logout();
|
||||
navigate("/login", { replace: true });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background text-foreground">
|
||||
<div className="flex min-h-screen">
|
||||
<aside className="hidden w-64 flex-col border-r border-border bg-card/40 md:flex">
|
||||
<div className="flex h-16 items-center border-b border-border px-6">
|
||||
<span className="text-lg font-semibold tracking-tight">Wisecolt CI</span>
|
||||
</div>
|
||||
<nav className="flex-1 space-y-1 px-3 py-4">
|
||||
{navigation.map((item) => (
|
||||
<NavLink
|
||||
key={item.to}
|
||||
to={item.to}
|
||||
className={({ isActive }) =>
|
||||
cn(
|
||||
"flex items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition",
|
||||
isActive
|
||||
? "bg-primary text-primary-foreground shadow-sm"
|
||||
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
||||
)
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon icon={item.icon} className="h-4 w-4" />
|
||||
<span>{item.label}</span>
|
||||
</NavLink>
|
||||
))}
|
||||
</nav>
|
||||
<div className="mt-auto space-y-3 border-t border-border px-4 py-4">
|
||||
<div className="flex gap-3">
|
||||
<ThemeToggle size="icon" className="h-10 w-10 justify-center" />
|
||||
<div className="flex h-10 flex-1 items-center gap-3 rounded-md border border-border bg-background px-3">
|
||||
<FontAwesomeIcon icon={faUser} className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="text-sm font-medium text-foreground">{user?.username ?? "-"}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="w-full justify-center gap-2"
|
||||
onClick={handleLogout}
|
||||
disabled={isLoggingOut}
|
||||
>
|
||||
<FontAwesomeIcon icon={faArrowRightFromBracket} className="h-4 w-4" />
|
||||
Çıkış Yap
|
||||
</Button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main className="flex-1">
|
||||
<div className="mx-auto flex max-w-5xl flex-col gap-6 px-4 py-8 sm:px-6 lg:px-8">
|
||||
<header className="flex items-center justify-between rounded-md border border-border bg-card/60 px-4 py-3">
|
||||
<div>
|
||||
<div className="text-sm uppercase tracking-wide text-muted-foreground">Proje</div>
|
||||
<div className="text-lg font-semibold text-foreground">Wisecolt CI</div>
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
Bağlantı: <span className="font-mono text-foreground">{socketUrl}</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="grid gap-6">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user