/
tsps
/
lk
Обзор
Документация
Войти
/
tsps
/
lk
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
src/components/layout/AppLayout.tsx
98 строк
4 KB
Василий Петров
Саммаризация транскрипции
04 май 2026, 21:54
04 май 2026, 21:54
84064ea
Код
Авторство
О чём код?
import { Outlet, useLocation } from "react-router-dom"; import { useAudioTranscriptionPolling } from "@/hooks/useAudioTranscriptionPolling"; import { useSummaryPolling } from "@/hooks/useSummaryPolling"; // для поллинга суммаризации import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; import { AppSidebar } from "./AppSidebar"; import { Button } from "@/components/ui/button"; import { UserCircle, Settings, LogOut } from "lucide-react"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { useNavigate } from "react-router-dom"; import { useAuthStore } from "@/store/authStore"; export function AppLayout() { const navigate = useNavigate(); // хук для навигации const judge = useAuthStore((state) => state.judge); // данные судьи const logout = useAuthStore((state) => state.logout); // метод выхода const location = useLocation(); useAudioTranscriptionPolling(); // запуск поллинга useSummaryPolling(); const handleLogout = () => { logout(); // очищает Zustand и localStorage navigate("/login", { replace: true }); // перенаправляем на логин }; const getPageTitle = (pathname: string) => { if (pathname.startsWith("/documents/")) return "Просмотр документа"; if (pathname.startsWith("/audio-recordings/")) return "Просмотр аудиозаписи"; switch (pathname) { case "/dashboard": return "Главная"; case "/documents": return "Документы"; case "/audio-recordings": return "Аудиозаписи"; default: return "Цифровой Помощник Судьи"; } }; const fullName = judge ? `${judge.last_name} ${judge.first_name} ${judge.middle_name}` : "Загрузка..."; return ( <SidebarProvider> <div className="min-h-screen flex w-full bg-gradient-card"> <AppSidebar /> <div className="flex-1 flex flex-col"> {/* Header */} <header className="border-b bg-card/80 backdrop-blur-sm px-6 py-4 flex items-center justify-between shadow-sm"> <div className="flex items-center gap-4"> <SidebarTrigger className="md:hidden" /> <div> <h1 className="text-2xl font-semibold text-judicial-navy"> {getPageTitle(location.pathname)} </h1> </div> </div> <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="ghost" className="flex items-center gap-2"> <UserCircle className="h-5 w-5" /> <span className="hidden md:inline">{fullName}</span> </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end" className="w-56"> <DropdownMenuItem className="flex items-center gap-2"> <Settings className="h-4 w-4" /> Настройки </DropdownMenuItem> <DropdownMenuItem className="flex items-center gap-2 text-destructive" onSelect={(e) => { e.preventDefault(); // предотвращаем дефолтное действие handleLogout(); }} > <LogOut className="h-4 w-4" /> Выход </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </header> {/* Main Content */} <main className="flex-1 p-6"> <Outlet /> </main> </div> </div> </SidebarProvider> ); }