"use client"; import { useEffect, useState, useRef } from "react"; import { Brain, Send, Paperclip, MoreHorizontal, Search, MessageSquare, Plus, FileText, CheckCircle2, Trash2 } from "lucide-react"; import { createClient } from "@/lib/supabase/client"; import { v4 as uuidv4 } from "uuid"; interface ChatSession { id: string; title: string; created_at: string; } interface ChatMessage { id: string; session_id: string; role: "user" | "assistant" | "system"; content: string; created_at: string; } export default function AIChatPage() { const [supabase] = useState(() => createClient()); const [sessions, setSessions] = useState([]); const [activeSessionId, setActiveSessionId] = useState(null); const [messages, setMessages] = useState([]); const [input, setInput] = useState(""); const [isLoading, setIsLoading] = useState(false); const messagesEndRef = useRef(null); // Auto-scroll to bottom const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }; useEffect(() => { scrollToBottom(); }, [messages]); // 1. Fetch Sessions on mount useEffect(() => { const fetchSessions = async () => { const { data: { user } } = await supabase.auth.getUser(); if (!user) return; const { data } = await supabase .from("chat_sessions") .select("*") .eq("user_id", user.id) .order("updated_at", { ascending: false }); if (data) { setSessions(data); if (data.length > 0) { setActiveSessionId(data[0].id); } } }; fetchSessions(); }, [supabase]); // 2. Fetch Messages when session changes useEffect(() => { if (!activeSessionId) return; const fetchMessages = async () => { const { data } = await supabase .from("chat_messages") .select("*") .eq("session_id", activeSessionId) .order("created_at", { ascending: true }); if (data) { setMessages(data as ChatMessage[]); } }; fetchMessages(); // Subscribe to real-time changes const channel = supabase .channel(`chat:${activeSessionId}`) .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'chat_messages', filter: `session_id=eq.${activeSessionId}` }, (payload) => { setMessages(prev => { if (prev.find(m => m.id === payload.new.id)) return prev; return [...prev, payload.new as ChatMessage]; }); }) .subscribe(); return () => { supabase.removeChannel(channel); }; }, [activeSessionId, supabase]); const handleNewChat = async () => { const { data: { user } } = await supabase.auth.getUser(); if (!user) return; const newSession = { user_id: user.id, title: "Yeni Sohbet", updated_at: new Date().toISOString() }; const { data, error } = await supabase .from("chat_sessions") .insert(newSession) .select() .single(); if (data) { setSessions([data, ...sessions]); setActiveSessionId(data.id); setMessages([]); } }; const handleSend = async (e?: React.FormEvent) => { if (e) e.preventDefault(); if (!input.trim() || isLoading) return; const userMessageContent = input.trim(); setInput(""); // Ensure we have a session let sessionId = activeSessionId; const { data: { user } } = await supabase.auth.getUser(); if (!user) return; if (!sessionId) { const { data: newSess } = await supabase .from("chat_sessions") .insert({ user_id: user.id, title: userMessageContent.slice(0, 30) + "..." }) .select() .single(); if (newSess) { sessionId = newSess.id; setActiveSessionId(sessionId); setSessions([newSess, ...sessions]); } else return; } const resolvedSessionId = sessionId; if (!resolvedSessionId) return; setIsLoading(true); // 1. Optimistic Update: Add User Message locally const optimisticUserMsg: ChatMessage = { id: uuidv4(), session_id: resolvedSessionId, role: "user", content: userMessageContent, created_at: new Date().toISOString() }; setMessages(prev => [...prev, optimisticUserMsg]); // 2. Save User Message to Supabase await supabase.from("chat_messages").insert({ id: optimisticUserMsg.id, session_id: resolvedSessionId, role: "user", content: userMessageContent }); try { // 3. Fetch AI preferences for API call const { data: settings } = await supabase .from("user_settings") .select("*") .eq("user_id", user.id) .single(); const provider = settings?.ai_model || localStorage.getItem("mindspace_ai_provider") || "gemini"; const apiKey = settings?.api_key || localStorage.getItem("mindspace_api_key") || ""; // 4. Call AI API const res = await fetch("/api/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ provider, apiKey, userMessageContent }), }); if (!res.ok) throw new Error("AI API Error"); const data = await res.json(); // 5. Optimistic Update: Add Assistant Message locally const assistantMsg: ChatMessage = { id: uuidv4(), session_id: resolvedSessionId, role: "assistant", content: data.reply || "Cevap üretilemedi.", created_at: new Date().toISOString() }; setMessages(prev => [...prev, assistantMsg]); // 6. Save Assistant Message to Supabase await supabase.from("chat_messages").insert({ id: assistantMsg.id, session_id: resolvedSessionId, role: "assistant", content: assistantMsg.content }); // 7. Update session title if it was default const currentSession = sessions.find(s => s.id === resolvedSessionId); if (currentSession?.title === "Yeni Sohbet") { const newTitle = userMessageContent.slice(0, 40); await supabase.from("chat_sessions").update({ title: newTitle }).eq("id", resolvedSessionId); setSessions(prev => prev.map(s => s.id === resolvedSessionId ? { ...s, title: newTitle } : s)); } } catch (error) { console.error(error); const errorMsg: ChatMessage = { id: uuidv4(), session_id: resolvedSessionId, role: "assistant", content: "Hata oluştu. Lütfen Ayarlar sayfasından API anahtarınızı kontrol edin.", created_at: new Date().toISOString() }; setMessages(prev => [...prev, errorMsg]); await supabase.from("chat_messages").insert({ id: errorMsg.id, session_id: resolvedSessionId, role: "assistant", content: errorMsg.content }); } finally { setIsLoading(false); } }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleSend(); } }; const deleteSession = async (id: string, e: React.MouseEvent) => { e.stopPropagation(); await supabase.from("chat_sessions").delete().eq("id", id); setSessions(prev => prev.filter(s => s.id !== id)); if (activeSessionId === id) { setActiveSessionId(null); setMessages([]); } }; return (
{/* Top Header */}

MindSpace / AI Assistant

{/* Main Chat Interface */}
{/* Left Sidebar: Chat Sessions */}
Recent Conversations
{sessions.map((session) => (
setActiveSessionId(session.id)} className={`group flex items-center gap-3 p-3 rounded-sm cursor-pointer transition-colors ${activeSessionId === session.id ? 'bg-[#1F172B] border border-primary/30 text-primary' : 'hover:bg-white/5 text-muted-foreground hover:text-foreground border border-transparent'}`} >
{session.title}
{new Date(session.created_at).toLocaleDateString()}
))}
{/* Right Side: Active Chat Area */}
{/* Chat Messages Area */}
{messages.length === 0 && !isLoading && (

Hello! I am your MindSpace AI Assistant.

Start a conversation or select a session from history.

)} {messages.map((m) => (
{m.role === "assistant" && (
)}

{m.content}

{m.role === "user" && (
ME
)}
))} {isLoading && (
MindSpace AI is thinking...
)}
{/* Chat Input Box */}