'use client'; import { useEffect, useState } from 'react'; import { IconLayoutSidebar, IconMessage, IconPlus, IconRobot, IconSend, IconSettings, IconUser, } from '@tabler/icons-react'; import { ActionIcon, AppShell, Avatar, Burger, Container, Group, Paper, rem, ScrollArea, Stack, Text, TextInput, Title, Tooltip, UnstyledButton, useMantineTheme, } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; import { useThemeContext } from '@/components/DynamicThemeProvider'; import { SettingsModal } from '@/components/Settings/SettingsModal'; interface Message { id: string; role: 'user' | 'assistant'; content: string; } interface Chat { id: string; title: string; updatedAt: string; messages?: Message[]; } export default function ChatLayout() { const [mobileOpened, { toggle: toggleMobile }] = useDisclosure(); const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true); const [settingsOpened, { open: openSettings, close: closeSettings }] = useDisclosure(false); const { primaryColor, setPrimaryColor } = useThemeContext(); const theme = useMantineTheme(); // State const [chats, setChats] = useState([]); const [activeChatId, setActiveChatId] = useState(null); const [messages, setMessages] = useState([ { id: '1', role: 'assistant', content: 'Hello! I am an AI assistant. How can I help you today?', }, ]); const [inputValue, setInputValue] = useState(''); const [isInputFocused, setIsInputFocused] = useState(false); const [isLoadingChats, setIsLoadingChats] = useState(false); // Fetch chats on load useEffect(() => { fetchChats(); }, [settingsOpened]); // Refresh when settings close (might have logged in/out) const fetchChats = async () => { setIsLoadingChats(true); try { const res = await fetch('/api/chats'); if (res.ok) { const data = await res.json(); if (Array.isArray(data)) { setChats(data); } else { setChats([]); } } else { setChats([]); } } catch (e) { console.error('Failed to fetch chats', e); setChats([]); } finally { setIsLoadingChats(false); } }; const handleSelectChat = (chat: Chat) => { setActiveChatId(chat.id); if (chat.messages) { setMessages(chat.messages); } else { // In a real app we might fetch full messages here if not included in list setMessages([]); } if (mobileOpened) { toggleMobile(); } }; const handleNewChat = () => { setActiveChatId(null); setMessages([ { id: Date.now().toString(), role: 'assistant', content: 'Hello! I am an AI assistant. How can I help you today?', }, ]); if (mobileOpened) { toggleMobile(); } }; const handleSendMessage = async () => { if (!inputValue.trim()) { return; } const userMessage: Message = { id: Date.now().toString(), role: 'user', content: inputValue, }; // Optimistic update const newMessages = [...messages, userMessage]; setMessages(newMessages); setInputValue(''); try { // Save to backend const res = await fetch('/api/chats', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ messages: [userMessage], chatId: activeChatId, }), }); if (res.ok) { const data = await res.json(); if (data.chatId && data.chatId !== activeChatId) { setActiveChatId(data.chatId); fetchChats(); // Refresh list to show new chat } // Simulate AI response setTimeout(async () => { const responseMessage: Message = { id: (Date.now() + 1).toString(), role: 'assistant', content: 'I am a simulated AI response. I do not have a backend yet. I just repeat that I am simulated.', }; const updatedMessages = [...newMessages, responseMessage]; setMessages(updatedMessages); // Save AI response to backend try { await fetch('/api/chats', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ messages: [responseMessage], chatId: data.chatId || activeChatId, }), }); } catch (e) { console.error(e); } }, 1000); } } catch (e) { console.error('Failed to save message', e); } }; const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { handleSendMessage(); } }; return ( <> AI Chat History {chats.length > 0 ? ( chats.map((chat) => ( handleSelectChat(chat)} p="sm" style={{ borderRadius: 'var(--mantine-radius-md)', backgroundColor: activeChatId === chat.id ? 'var(--mantine-color-default-hover)' : 'transparent', transition: 'background-color 0.2s', }} > {chat.title} )) ) : ( {isLoadingChats ? 'Loading...' : 'No saved chats'} )} {messages.map((message) => ( {message.role === 'assistant' && ( )} {message.content} {message.role === 'user' && ( )} ))} setInputValue(event.currentTarget.value)} onKeyDown={handleKeyDown} onFocus={() => setIsInputFocused(true)} onBlur={() => setIsInputFocused(false)} style={{ flex: 1, paddingLeft: rem(10) }} size="md" /> ); }