"use client";
import { LogOut, MessageSquare, Plus, Search, Trash2, X } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import type { AuthIdentity } from "@/lib/auth/types";
import type { Conversation } from "@/lib/chat/types";
import { cn } from "@/lib/utils";
type ChatSidebarProps = {
activeConversationId: string | null;
conversations: Conversation[];
onClose?: () => void;
onDeleteConversation: (id: string) => void;
onLogout: () => void;
onNewConversation: () => void;
onSelectConversation: (id: string) => void;
user: AuthIdentity;
};
export function ChatSidebar({
activeConversationId,
conversations,
onClose,
onDeleteConversation,
onLogout,
onNewConversation,
onSelectConversation,
user,
}: ChatSidebarProps) {
const [query, setQuery] = useState("");
const filtered = conversations.filter((conversation) =>
conversation.title.toLocaleLowerCase("ru").includes(query.trim().toLocaleLowerCase("ru")),
);
return (
<nav
aria-label="История чатов"
className="flex h-full w-[272px] flex-col bg-sidebar text-sidebar-foreground"
>
<div className="flex h-14 items-center justify-between px-4">
<p className="font-semibold tracking-tight">AI Control Center</p>
{onClose ? (
<Button
aria-label="Закрыть меню"
onClick={onClose}
size="icon"
type="button"
variant="ghost"
>
<X aria-hidden="true" />
</Button>
) : null}
</div>
<div className="px-3 pb-3">
<Button
className="w-full justify-start"
onClick={() => {
onNewConversation();
onClose?.();
}}
type="button"
variant="outline"
>
<Plus aria-hidden="true" />
Новый чат
</Button>
</div>
{conversations.length ? (
<div className="relative px-3 pb-2">
<Search
aria-hidden="true"
className="absolute left-5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground"
/>
<Input
aria-label="Поиск по чатам"
className="h-8 bg-background pl-8 text-xs"
onChange={(event) => setQuery(event.target.value)}
placeholder="Найти чат"
value={query}
/>
</div>
) : null}
<div className="min-h-0 flex-1 overflow-y-auto px-2 pb-3">
{filtered.length ? (
<ul className="space-y-0.5">
{filtered.map((conversation) => {
const active = conversation.id === activeConversationId;
return (
<li
className={cn(
"group flex items-center rounded-lg pr-1 hover:bg-sidebar-accent",
active && "bg-sidebar-accent",
)}
key={conversation.id}
>
<button
aria-current={active ? "page" : undefined}
className="flex min-w-0 flex-1 items-center gap-2 rounded-lg px-2 py-2 text-left text-sm outline-none focus-visible:ring-2 focus-visible:ring-sidebar-ring"
onClick={() => {
onSelectConversation(conversation.id);
onClose?.();
}}
type="button"
>
<MessageSquare aria-hidden="true" className="size-3.5 shrink-0" />
<span className="truncate">{conversation.title}</span>
</button>
<Button
aria-label={`Удалить чат ${conversation.title}`}
className="opacity-70 md:opacity-0 md:group-hover:opacity-100 md:focus-visible:opacity-100"
onClick={() => onDeleteConversation(conversation.id)}
size="icon-xs"
title={`Удалить чат ${conversation.title}`}
type="button"
variant="ghost"
>
<Trash2 aria-hidden="true" />
</Button>
</li>
);
})}
</ul>
) : (
<p className="px-3 py-6 text-center text-xs leading-5 text-muted-foreground">
{conversations.length ? "Ничего не найдено" : "Здесь появятся ваши диалоги"}
</p>
)}
</div>
<div className="border-t border-sidebar-border p-3">
<div className="flex items-center gap-2 rounded-lg px-2 py-2">
<div className="grid size-8 shrink-0 place-items-center rounded-full bg-sidebar-primary text-xs font-semibold text-sidebar-primary-foreground">
{initials(user.firstName, user.lastName, user.email)}
</div>
<div className="min-w-0 flex-1">
<p className="truncate text-xs font-medium">{user.fullName}</p>
<p className="truncate text-[11px] text-muted-foreground">{user.position}</p>
<p className="truncate text-[11px] text-muted-foreground">{user.email}</p>
{user.roles.length ? (
<p className="truncate text-[11px] text-muted-foreground">
{user.roles.join(", ")}
</p>
) : null}
</div>
<Button
aria-label="Выйти"
onClick={onLogout}
size="icon-sm"
title="Выйти"
type="button"
variant="ghost"
>
<LogOut aria-hidden="true" />
</Button>
</div>
</div>
</nav>
);
}
function initials(firstName: string, lastName: string, email: string): string {
return (
`${firstName.at(0) ?? ""}${lastName.at(0) ?? ""}`.toUpperCase() ||
email.slice(0, 1).toUpperCase()
);
}