Domify-Academy-Bot / ChatSidebar.tsx
Domify's picture
Upload 35 files
93c19dc verified
import { useState, useEffect } from "react";
import { Plus, Trash2, ChevronLeft, ChevronRight } from "lucide-react";
/**
* ChatSidebar Component
*
* Features:
* - Display chat history from local storage
* - Create new chat
* - Delete chat history
* - Switch between chats
* - Collapsible sidebar
* - Glassmorphism UI matching theme
*/
export interface ChatSession {
id: string;
title: string;
timestamp: number;
mode: "ask" | "imagine";
messageCount: number;
}
interface ChatSidebarProps {
currentChatId: string | null;
onNewChat: () => void;
onSelectChat: (chatId: string) => void;
onDeleteChat: (chatId: string) => void;
isOpen: boolean;
onToggle: () => void;
}
export default function ChatSidebar({
currentChatId,
onNewChat,
onSelectChat,
onDeleteChat,
isOpen,
onToggle,
}: ChatSidebarProps) {
const [chats, setChats] = useState<ChatSession[]>([]);
// Load chats from local storage
useEffect(() => {
const savedChats = localStorage.getItem("domify_chats");
if (savedChats) {
try {
const parsed = JSON.parse(savedChats);
setChats(parsed.sort((a: ChatSession, b: ChatSession) => b.timestamp - a.timestamp));
} catch (error) {
console.error("Error loading chats:", error);
}
}
}, []);
// Handle delete chat
const handleDelete = (chatId: string, e: React.MouseEvent) => {
e.stopPropagation();
// Remove from local storage
const savedChats = localStorage.getItem("domify_chats");
if (savedChats) {
const parsed = JSON.parse(savedChats);
const filtered = parsed.filter((c: ChatSession) => c.id !== chatId);
localStorage.setItem("domify_chats", JSON.stringify(filtered));
setChats(filtered);
}
// Also remove the chat messages
localStorage.removeItem(`domify_chat_${chatId}`);
onDeleteChat(chatId);
};
// Format date
const formatDate = (timestamp: number) => {
const date = new Date(timestamp);
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
if (date.toDateString() === today.toDateString()) {
return date.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" });
} else if (date.toDateString() === yesterday.toDateString()) {
return "Yesterday";
} else {
return date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
}
};
return (
<>
{/* Sidebar */}
<div
className={`fixed left-0 top-0 h-screen glass-panel-lg rounded-none border-r border-white/10 transition-all duration-300 z-40 flex flex-col ${
isOpen ? "w-64" : "w-0"
} overflow-hidden`}
>
{/* Header */}
<div className="p-4 border-b border-white/10 flex items-center justify-between">
<h2 className="text-lg font-semibold gradient-text">Chats</h2>
<button
onClick={onToggle}
className="p-2 hover:bg-white/5 rounded-lg transition-smooth"
title="Close sidebar"
>
<ChevronLeft size={20} />
</button>
</div>
{/* New Chat Button */}
<div className="p-4 border-b border-white/10">
<button
onClick={onNewChat}
className="w-full flex items-center justify-center gap-2 px-4 py-2 rounded-lg bg-primary/20 text-primary border border-primary/30 hover:bg-primary/30 transition-smooth"
>
<Plus size={18} />
<span>New Chat</span>
</button>
</div>
{/* Chat List */}
<div className="flex-1 overflow-y-auto scrollbar-thin p-2 space-y-2">
{chats.length === 0 ? (
<div className="text-center py-8 text-muted-foreground text-sm">
<p>No chats yet</p>
<p className="text-xs mt-2">Start a new conversation</p>
</div>
) : (
chats.map((chat) => (
<button
key={chat.id}
onClick={() => onSelectChat(chat.id)}
className={`w-full text-left p-3 rounded-lg transition-smooth group ${
currentChatId === chat.id
? "bg-primary/20 border border-primary/30"
: "hover:bg-white/5 border border-transparent"
}`}
>
<div className="flex items-start justify-between gap-2">
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate text-foreground">
{chat.title}
</p>
<div className="flex items-center gap-2 mt-1">
<span className="text-xs text-muted-foreground">
{formatDate(chat.timestamp)}
</span>
<span className="text-xs px-2 py-0.5 rounded bg-white/5 text-muted-foreground">
{chat.mode === "ask" ? "💬" : "🎨"} {chat.messageCount}
</span>
</div>
</div>
{/* Delete Button */}
<button
onClick={(e) => handleDelete(chat.id, e)}
className="p-1.5 hover:bg-destructive/20 rounded transition-smooth opacity-0 group-hover:opacity-100"
title="Delete chat"
>
<Trash2 size={16} className="text-destructive" />
</button>
</div>
</button>
))
)}
</div>
{/* Footer */}
<div className="p-4 border-t border-white/10 text-xs text-muted-foreground text-center">
<p>Chats stored locally</p>
</div>
</div>
{/* Toggle Button (when sidebar is closed) */}
{!isOpen && (
<button
onClick={onToggle}
className="fixed left-4 top-4 z-40 p-2 glass-panel hover:bg-white/10 transition-smooth"
title="Open sidebar"
>
<ChevronRight size={20} />
</button>
)}
{/* Overlay (when sidebar is open on mobile) */}
{isOpen && (
<div
className="fixed inset-0 bg-black/20 backdrop-blur-sm z-30 md:hidden"
onClick={onToggle}
/>
)}
</>
);
}