Primeiro Commit
This commit is contained in:
+300
-134
@@ -1,8 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Search, Folder, FolderPlus, MessageSquare, MoreVertical, Trash2, Edit, FolderInput, ChevronLeft, ChevronRight, Plus } from "lucide-react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { chatService, StoredChat, StoredFolder } from "@/services/chat";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import { ptBR } from "date-fns/locale";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
@@ -30,111 +34,153 @@ import {
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
|
||||
interface Conversation {
|
||||
id: string;
|
||||
title: string;
|
||||
lastMessage: string;
|
||||
timestamp: string;
|
||||
folderId?: string;
|
||||
}
|
||||
|
||||
interface ChatFolder {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface ChatSidebarProps {
|
||||
isCollapsed: boolean;
|
||||
onToggleCollapse: () => void;
|
||||
onNewChat: () => void;
|
||||
onSelectChat?: (chat: StoredChat) => void;
|
||||
currentChatId?: string;
|
||||
}
|
||||
|
||||
export const ChatSidebar = ({ isCollapsed, onToggleCollapse, onNewChat }: ChatSidebarProps) => {
|
||||
export const ChatSidebar = ({ isCollapsed, onToggleCollapse, onNewChat, onSelectChat, currentChatId }: ChatSidebarProps) => {
|
||||
const { toast } = useToast();
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [isCreateFolderOpen, setIsCreateFolderOpen] = useState(false);
|
||||
const [isEditFolderOpen, setIsEditFolderOpen] = useState(false);
|
||||
const [isDeleteFolderOpen, setIsDeleteFolderOpen] = useState(false);
|
||||
const [isDeleteChatOpen, setIsDeleteChatOpen] = useState(false);
|
||||
const [newFolderName, setNewFolderName] = useState("");
|
||||
const [editingFolder, setEditingFolder] = useState<ChatFolder | null>(null);
|
||||
const [deletingFolder, setDeletingFolder] = useState<ChatFolder | null>(null);
|
||||
const [selectedConversation, setSelectedConversation] = useState<string | null>("1");
|
||||
const [editingFolder, setEditingFolder] = useState<StoredFolder | null>(null);
|
||||
const [deletingFolder, setDeletingFolder] = useState<StoredFolder | null>(null);
|
||||
const [deletingChat, setDeletingChat] = useState<StoredChat | null>(null);
|
||||
|
||||
const [folders, setFolders] = useState<ChatFolder[]>([
|
||||
{ id: "work", name: "Trabalho" },
|
||||
{ id: "personal", name: "Pessoal" },
|
||||
]);
|
||||
// Estado carregado do localStorage via chatService
|
||||
const [chats, setChats] = useState<StoredChat[]>([]);
|
||||
const [folders, setFolders] = useState<StoredFolder[]>([]);
|
||||
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
|
||||
|
||||
const [conversations, setConversations] = useState<Conversation[]>([
|
||||
{
|
||||
id: "1",
|
||||
title: "Conversa sobre IA",
|
||||
lastMessage: "Como funciona o machine learning?",
|
||||
timestamp: "Há 5 min",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
title: "Projeto HGTX",
|
||||
lastMessage: "Discutindo arquitetura do sistema",
|
||||
timestamp: "Há 1 hora",
|
||||
folderId: "work",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
title: "Ideias criativas",
|
||||
lastMessage: "Brainstorm para novo produto",
|
||||
timestamp: "Ontem",
|
||||
folderId: "personal",
|
||||
},
|
||||
]);
|
||||
// Carrega chats e pastas do localStorage quando o componente monta
|
||||
useEffect(() => {
|
||||
loadChatsAndFolders();
|
||||
|
||||
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set(["work", "personal"]));
|
||||
// Escuta evento customizado para recarregar quando chat é atualizado
|
||||
const handleChatUpdate = () => {
|
||||
loadChatsAndFolders();
|
||||
};
|
||||
|
||||
window.addEventListener('chatUpdated', handleChatUpdate);
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
window.removeEventListener('chatUpdated', handleChatUpdate);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const loadChatsAndFolders = () => {
|
||||
const loadedChats = chatService.getAllChats();
|
||||
const loadedFolders = chatService.getAllFolders();
|
||||
|
||||
setChats(loadedChats);
|
||||
setFolders(loadedFolders);
|
||||
|
||||
// Expande todas as pastas por padrão
|
||||
setExpandedFolders(new Set(loadedFolders.map(f => f.id)));
|
||||
};
|
||||
|
||||
const handleCreateFolder = () => {
|
||||
if (newFolderName.trim()) {
|
||||
const newFolder: ChatFolder = {
|
||||
id: Date.now().toString(),
|
||||
name: newFolderName,
|
||||
};
|
||||
setFolders([...folders, newFolder]);
|
||||
setNewFolderName("");
|
||||
setIsCreateFolderOpen(false);
|
||||
try {
|
||||
const newFolder: StoredFolder = {
|
||||
id: chatService.generateChatId(), // Usa mesmo gerador de ID
|
||||
name: newFolderName,
|
||||
createdAt: new Date(),
|
||||
chatIds: [],
|
||||
};
|
||||
chatService.saveFolder(newFolder);
|
||||
loadChatsAndFolders();
|
||||
setNewFolderName("");
|
||||
setIsCreateFolderOpen(false);
|
||||
|
||||
toast({
|
||||
title: "Pasta criada",
|
||||
description: `Pasta "${newFolderName}" criada com sucesso.`,
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "Erro ao criar pasta",
|
||||
description: "Não foi possível criar a pasta. Tente novamente.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditFolder = () => {
|
||||
if (editingFolder && newFolderName.trim()) {
|
||||
setFolders(
|
||||
folders.map((f) =>
|
||||
f.id === editingFolder.id ? { ...f, name: newFolderName } : f
|
||||
)
|
||||
);
|
||||
setNewFolderName("");
|
||||
setEditingFolder(null);
|
||||
setIsEditFolderOpen(false);
|
||||
try {
|
||||
const updatedFolder: StoredFolder = {
|
||||
...editingFolder,
|
||||
name: newFolderName,
|
||||
};
|
||||
chatService.saveFolder(updatedFolder);
|
||||
loadChatsAndFolders();
|
||||
setNewFolderName("");
|
||||
setEditingFolder(null);
|
||||
setIsEditFolderOpen(false);
|
||||
|
||||
toast({
|
||||
title: "Pasta renomeada",
|
||||
description: `Pasta renomeada para "${newFolderName}".`,
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "Erro ao renomear pasta",
|
||||
description: "Não foi possível renomear a pasta. Tente novamente.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteFolder = () => {
|
||||
if (deletingFolder) {
|
||||
// Remove folder and move conversations back to "no folder"
|
||||
setConversations(
|
||||
conversations.map((conv) =>
|
||||
conv.folderId === deletingFolder.id ? { ...conv, folderId: undefined } : conv
|
||||
)
|
||||
);
|
||||
setFolders(folders.filter((f) => f.id !== deletingFolder.id));
|
||||
setDeletingFolder(null);
|
||||
setIsDeleteFolderOpen(false);
|
||||
try {
|
||||
// Remove chats da pasta (volta para "Sem Pasta")
|
||||
const updatedChats = chats.map(chat => {
|
||||
if (chat.folderId === deletingFolder.id) {
|
||||
const updated = { ...chat, folderId: undefined };
|
||||
chatService.saveChat(updated);
|
||||
return updated;
|
||||
}
|
||||
return chat;
|
||||
});
|
||||
|
||||
chatService.deleteFolder(deletingFolder.id);
|
||||
loadChatsAndFolders();
|
||||
setDeletingFolder(null);
|
||||
setIsDeleteFolderOpen(false);
|
||||
|
||||
toast({
|
||||
title: "Pasta excluída",
|
||||
description: "As conversas foram movidas para 'Sem Pasta'.",
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "Erro ao excluir pasta",
|
||||
description: "Não foi possível excluir a pasta. Tente novamente.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const openEditFolder = (folder: ChatFolder) => {
|
||||
const openEditFolder = (folder: StoredFolder) => {
|
||||
setEditingFolder(folder);
|
||||
setNewFolderName(folder.name);
|
||||
setIsEditFolderOpen(true);
|
||||
};
|
||||
|
||||
const openDeleteFolder = (folder: ChatFolder) => {
|
||||
const openDeleteFolder = (folder: StoredFolder) => {
|
||||
setDeletingFolder(folder);
|
||||
setIsDeleteFolderOpen(true);
|
||||
};
|
||||
@@ -149,37 +195,112 @@ export const ChatSidebar = ({ isCollapsed, onToggleCollapse, onNewChat }: ChatSi
|
||||
setExpandedFolders(newExpanded);
|
||||
};
|
||||
|
||||
const moveToFolder = (conversationId: string, folderId: string) => {
|
||||
setConversations(
|
||||
conversations.map((conv) =>
|
||||
conv.id === conversationId ? { ...conv, folderId } : conv
|
||||
)
|
||||
);
|
||||
const moveToFolder = (chatId: string, folderId: string) => {
|
||||
try {
|
||||
const chat = chats.find(c => c.id === chatId);
|
||||
if (chat) {
|
||||
const updatedChat: StoredChat = {
|
||||
...chat,
|
||||
folderId: folderId,
|
||||
};
|
||||
chatService.saveChat(updatedChat);
|
||||
loadChatsAndFolders();
|
||||
|
||||
const folder = folders.find(f => f.id === folderId);
|
||||
toast({
|
||||
title: "Chat movido",
|
||||
description: `Movido para a pasta "${folder?.name}".`,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "Erro ao mover chat",
|
||||
description: "Não foi possível mover o chat. Tente novamente.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const removeFromFolder = (conversationId: string) => {
|
||||
setConversations(
|
||||
conversations.map((conv) =>
|
||||
conv.id === conversationId ? { ...conv, folderId: undefined } : conv
|
||||
)
|
||||
);
|
||||
const removeFromFolder = (chatId: string) => {
|
||||
try {
|
||||
const chat = chats.find(c => c.id === chatId);
|
||||
if (chat) {
|
||||
const updatedChat: StoredChat = {
|
||||
...chat,
|
||||
folderId: undefined,
|
||||
};
|
||||
chatService.saveChat(updatedChat);
|
||||
loadChatsAndFolders();
|
||||
|
||||
toast({
|
||||
title: "Chat removido da pasta",
|
||||
description: "Chat movido para 'Sem Pasta'.",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "Erro ao remover chat",
|
||||
description: "Não foi possível remover o chat da pasta.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const filteredConversations = conversations.filter(
|
||||
(conv) =>
|
||||
conv.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
conv.lastMessage.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
const handleDeleteChat = () => {
|
||||
if (deletingChat) {
|
||||
try {
|
||||
chatService.deleteChat(deletingChat.id);
|
||||
loadChatsAndFolders();
|
||||
setDeletingChat(null);
|
||||
setIsDeleteChatOpen(false);
|
||||
|
||||
const conversationsWithoutFolder = filteredConversations.filter((c) => !c.folderId);
|
||||
const conversationsByFolder = folders.reduce((acc, folder) => {
|
||||
acc[folder.id] = filteredConversations.filter((c) => c.folderId === folder.id);
|
||||
toast({
|
||||
title: "Chat excluído",
|
||||
description: "A conversa foi excluída com sucesso.",
|
||||
});
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "Erro ao excluir chat",
|
||||
description: "Não foi possível excluir o chat. Tente novamente.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const openDeleteChat = (chat: StoredChat) => {
|
||||
setDeletingChat(chat);
|
||||
setIsDeleteChatOpen(true);
|
||||
};
|
||||
|
||||
const handleSelectChat = (chat: StoredChat) => {
|
||||
if (onSelectChat) {
|
||||
onSelectChat(chat);
|
||||
}
|
||||
};
|
||||
|
||||
// Filtrar chats pela busca
|
||||
const filteredChats = chats.filter((chat) => {
|
||||
const searchLower = searchQuery.toLowerCase();
|
||||
const titleMatch = chat.title.toLowerCase().includes(searchLower);
|
||||
const contentMatch = chat.messages.some(msg =>
|
||||
msg.content.toLowerCase().includes(searchLower)
|
||||
);
|
||||
return titleMatch || contentMatch;
|
||||
});
|
||||
|
||||
// Separar chats sem pasta
|
||||
const chatsWithoutFolder = filteredChats.filter((c) => !c.folderId);
|
||||
|
||||
// Agrupar chats por pasta
|
||||
const chatsByFolder = folders.reduce((acc, folder) => {
|
||||
acc[folder.id] = filteredChats.filter((c) => c.folderId === folder.id);
|
||||
return acc;
|
||||
}, {} as Record<string, Conversation[]>);
|
||||
}, {} as Record<string, StoredChat[]>);
|
||||
|
||||
if (isCollapsed) {
|
||||
return (
|
||||
<div className="w-12 border-r border-border bg-card/30 backdrop-blur-sm flex flex-col items-center py-4">
|
||||
<div className="w-12 h-full border-r border-border bg-card/30 backdrop-blur-sm flex flex-col items-center py-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@@ -193,7 +314,7 @@ export const ChatSidebar = ({ isCollapsed, onToggleCollapse, onNewChat }: ChatSi
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-80 border-r border-border bg-card/30 backdrop-blur-sm flex flex-col">
|
||||
<div className="w-80 h-full border-r border-border bg-card/30 backdrop-blur-sm flex flex-col">
|
||||
{/* Header with collapse button */}
|
||||
<div className="px-4 pt-4 pb-2 flex items-center justify-between">
|
||||
<h3 className="text-sm font-semibold text-foreground">Conversas</h3>
|
||||
@@ -330,10 +451,10 @@ export const ChatSidebar = ({ isCollapsed, onToggleCollapse, onNewChat }: ChatSi
|
||||
{folder.name}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{conversationsByFolder[folder.id]?.length || 0}
|
||||
{chatsByFolder[folder.id]?.length || 0}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
@@ -363,17 +484,18 @@ export const ChatSidebar = ({ isCollapsed, onToggleCollapse, onNewChat }: ChatSi
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
{expandedFolders.has(folder.id) && conversationsByFolder[folder.id]?.length > 0 && (
|
||||
{expandedFolders.has(folder.id) && chatsByFolder[folder.id]?.length > 0 && (
|
||||
<div className="ml-6 space-y-1">
|
||||
{conversationsByFolder[folder.id].map((conv) => (
|
||||
<ConversationItem
|
||||
key={conv.id}
|
||||
conversation={conv}
|
||||
isSelected={selectedConversation === conv.id}
|
||||
onSelect={() => setSelectedConversation(conv.id)}
|
||||
{chatsByFolder[folder.id].map((chat) => (
|
||||
<ChatItem
|
||||
key={chat.id}
|
||||
chat={chat}
|
||||
isSelected={currentChatId === chat.id}
|
||||
onSelect={() => handleSelectChat(chat)}
|
||||
folders={folders}
|
||||
onMoveToFolder={moveToFolder}
|
||||
onRemoveFromFolder={removeFromFolder}
|
||||
onDelete={() => openDeleteChat(chat)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -381,48 +503,90 @@ export const ChatSidebar = ({ isCollapsed, onToggleCollapse, onNewChat }: ChatSi
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Conversations without folder */}
|
||||
{conversationsWithoutFolder.length > 0 && (
|
||||
{/* Chats without folder */}
|
||||
{chatsWithoutFolder.length > 0 && (
|
||||
<div className="space-y-1">
|
||||
<div className="px-3 py-2 text-xs font-semibold text-muted-foreground uppercase tracking-wider">
|
||||
Sem Pasta
|
||||
</div>
|
||||
{conversationsWithoutFolder.map((conv) => (
|
||||
<ConversationItem
|
||||
key={conv.id}
|
||||
conversation={conv}
|
||||
isSelected={selectedConversation === conv.id}
|
||||
onSelect={() => setSelectedConversation(conv.id)}
|
||||
{chatsWithoutFolder.map((chat) => (
|
||||
<ChatItem
|
||||
key={chat.id}
|
||||
chat={chat}
|
||||
isSelected={currentChatId === chat.id}
|
||||
onSelect={() => handleSelectChat(chat)}
|
||||
folders={folders}
|
||||
onMoveToFolder={moveToFolder}
|
||||
onRemoveFromFolder={removeFromFolder}
|
||||
onDelete={() => openDeleteChat(chat)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
{/* Delete Chat Alert */}
|
||||
<AlertDialog open={isDeleteChatOpen} onOpenChange={setIsDeleteChatOpen}>
|
||||
<AlertDialogContent className="glass-effect bg-card border-border z-50">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Excluir Conversa?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Esta ação não pode ser desfeita. A conversa "{deletingChat?.title}" será permanentemente excluída.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancelar</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={handleDeleteChat} className="bg-destructive text-destructive-foreground hover:bg-destructive/90">
|
||||
Excluir
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface ConversationItemProps {
|
||||
conversation: Conversation;
|
||||
interface ChatItemProps {
|
||||
chat: StoredChat;
|
||||
isSelected: boolean;
|
||||
onSelect: () => void;
|
||||
folders: ChatFolder[];
|
||||
onMoveToFolder: (conversationId: string, folderId: string) => void;
|
||||
onRemoveFromFolder: (conversationId: string) => void;
|
||||
folders: StoredFolder[];
|
||||
onMoveToFolder: (chatId: string, folderId: string) => void;
|
||||
onRemoveFromFolder: (chatId: string) => void;
|
||||
onDelete: () => void;
|
||||
}
|
||||
|
||||
const ConversationItem = ({
|
||||
conversation,
|
||||
const ChatItem = ({
|
||||
chat,
|
||||
isSelected,
|
||||
onSelect,
|
||||
folders,
|
||||
onMoveToFolder,
|
||||
onRemoveFromFolder,
|
||||
}: ConversationItemProps) => {
|
||||
onDelete,
|
||||
}: ChatItemProps) => {
|
||||
// Pega a última mensagem do usuário
|
||||
const lastUserMessage = chat.messages
|
||||
.filter(m => m.role === 'user')
|
||||
.slice(-1)[0];
|
||||
|
||||
// Formata timestamp relativo
|
||||
const timeAgo = formatDistanceToNow(new Date(chat.updatedAt), {
|
||||
addSuffix: true,
|
||||
locale: ptBR,
|
||||
});
|
||||
|
||||
// Limita o título a 40 caracteres
|
||||
const truncatedTitle = chat.title.length > 40
|
||||
? chat.title.substring(0, 40) + '...'
|
||||
: chat.title;
|
||||
|
||||
// Limita a mensagem a 50 caracteres
|
||||
const truncatedMessage = lastUserMessage?.content.length > 50
|
||||
? lastUserMessage.content.substring(0, 50) + '...'
|
||||
: lastUserMessage?.content;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`group flex items-start gap-2 px-3 py-2 rounded-lg cursor-pointer transition-all ${
|
||||
@@ -433,13 +597,17 @@ const ConversationItem = ({
|
||||
onClick={onSelect}
|
||||
>
|
||||
<MessageSquare className="w-4 h-4 mt-0.5 text-primary flex-shrink-0" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium truncate">{conversation.title}</p>
|
||||
<p className="text-xs text-muted-foreground truncate">
|
||||
{conversation.lastMessage}
|
||||
<div className="flex-1 min-w-0 overflow-hidden">
|
||||
<p className="text-sm font-medium truncate" title={chat.title}>
|
||||
{truncatedTitle}
|
||||
</p>
|
||||
{lastUserMessage && (
|
||||
<p className="text-xs text-muted-foreground truncate" title={lastUserMessage.content}>
|
||||
{truncatedMessage}
|
||||
</p>
|
||||
)}
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
{conversation.timestamp}
|
||||
{timeAgo}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -448,21 +616,16 @@ const ConversationItem = ({
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-6 w-6 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
className="h-6 w-6 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0"
|
||||
>
|
||||
<MoreVertical className="w-3 h-3" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="glass-effect bg-popover border-border z-50">
|
||||
<DropdownMenuItem className="gap-2">
|
||||
<Edit className="w-3 h-3" />
|
||||
Renomear
|
||||
</DropdownMenuItem>
|
||||
|
||||
{conversation.folderId && (
|
||||
{chat.folderId && (
|
||||
<DropdownMenuItem
|
||||
className="gap-2"
|
||||
onClick={() => onRemoveFromFolder(conversation.id)}
|
||||
onClick={() => onRemoveFromFolder(chat.id)}
|
||||
>
|
||||
<FolderInput className="w-3 h-3" />
|
||||
Remover da Pasta
|
||||
@@ -473,14 +636,17 @@ const ConversationItem = ({
|
||||
<DropdownMenuItem
|
||||
key={folder.id}
|
||||
className="gap-2"
|
||||
onClick={() => onMoveToFolder(conversation.id, folder.id)}
|
||||
onClick={() => onMoveToFolder(chat.id, folder.id)}
|
||||
>
|
||||
<Folder className="w-3 h-3" />
|
||||
Mover para {folder.name}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
|
||||
<DropdownMenuItem className="gap-2 text-destructive">
|
||||
<DropdownMenuItem
|
||||
className="gap-2 text-destructive"
|
||||
onClick={onDelete}
|
||||
>
|
||||
<Trash2 className="w-3 h-3" />
|
||||
Excluir
|
||||
</DropdownMenuItem>
|
||||
|
||||
Reference in New Issue
Block a user