From 7a8c09c20278a21fc02c879bddb1d72b757e3b94 Mon Sep 17 00:00:00 2001 From: yoginawaka Date: Tue, 11 Feb 2025 18:31:29 +0000 Subject: [PATCH] Update app/dashboard/page.tsx --- app/dashboard/page.tsx | 1182 ++++++++++++++++++++-------------------- 1 file changed, 591 insertions(+), 591 deletions(-) diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index d8228ee..122dbc1 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,592 +1,592 @@ -'use client' - -import React, { useState, useEffect, useRef, useCallback } from 'react'; -import { v4 as uuidv4 } from 'uuid'; -import Cookies from 'js-cookie'; -import { usePrivy, useWallets } from '@privy-io/react-auth'; -import { useRouter } from 'next/navigation'; -import { Providers } from '@/components/providers/privy-provider'; -import { StarredChat } from '@/components/chat/sidebar/StarredChat'; -import { SidebarHeader } from '@/components/chat/sidebar/SidebarHeader'; -import { IntegrationButton } from '@/components/chat/IntegrationButton'; -import { ChatInput } from '@/components/chat/ChatInput'; -import { WelcomeHeader } from '@/components/chat/WelcomeHeader'; -import MessageBubble from '@/components/chat/MessageBubble'; -import { motion, AnimatePresence } from 'framer-motion'; -import { Settings, LogOut, Compass ,Landmark, Wrench, ScanSearch, Computer } from 'lucide-react'; -import Avatar, { genConfig } from 'react-nice-avatar'; -import logo from "@/public/assets/logo/landing-logo-blue.png" -import { NICKNAMES } from '@/components/chat/constants/nicknames'; - -interface Message { - id: string; - role: 'user' | 'assistant' | 'system'; - content: string; - timestamp: string; -} - -interface Conversation { - id: string; - title: string; - date: string; - messages: Message[]; - isStarred: boolean; -} - -function DashboardContent() { - const [conversations, setConversations] = useState([]); - const [messages, setMessages] = useState([]); - const [input, setInput] = useState(''); - const [isLoading, setIsLoading] = useState(false); - const [sessionId, setSessionId] = useState(() => uuidv4()); - const [currentConversation, setCurrentConversation] = useState(null); - const [isMobile, setIsMobile] = useState(false); - const [isSidebarOpen, setSidebarOpen] = useState(false); - const messagesEndRef = useRef(null); - const [showLogout, setShowLogout] = useState(false); - const [userName, setUserName] = useState('ALMAZE'); - const [avatarConfig, setAvatarConfig] = useState(() => genConfig()); - const { ready, authenticated, logout: privyLogout } = usePrivy(); - const router = useRouter(); - const { wallets } = useWallets(); - const sidebarTimeoutRef = useRef(); - const [isLongResponse, setIsLongResponse] = useState(false); - - //Random Username Generator - useEffect(() => { - const randomIndex = Math.floor(Math.random() * NICKNAMES.length); - const selectedName = NICKNAMES[randomIndex]; - setUserName(selectedName); - setAvatarConfig(genConfig(selectedName)); - }, []); - useEffect(() => { - const handleResize = () => { - const mobile = window.innerWidth <= 768; - setIsMobile(mobile); - setSidebarOpen(false); - }; - - handleResize(); - window.addEventListener('resize', handleResize); - return () => window.removeEventListener('resize', handleResize); - - }, []); - - const scrollToBottom = useCallback(() => { - messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); - }, []); - - const startNewChat = useCallback(() => { - const newSessionId = uuidv4(); - setSessionId(newSessionId); - setMessages([]); - setCurrentConversation(null); - setSidebarOpen(false); - // Force scroll to input - setTimeout(() => { - const inputElement = document.querySelector('input[type="text"]'); - (inputElement as HTMLInputElement)?.focus(); - }, 100); - }, [isMobile]); - - const handleStarChat = useCallback((id: string) => { - setConversations(prev => prev.map(conv => - conv.id === id ? { ...conv, isStarred: !conv.isStarred } : conv - )); - }, []); - - const loadConversation = useCallback((conversation: Conversation) => { - setSessionId(conversation.id); - setMessages(conversation.messages); - setCurrentConversation(conversation); - if (isMobile) setSidebarOpen(false); - }, [isMobile]); - - // Removed unused deleteConversation function - const handleSidebarHover = (isHovering: boolean) => { - if (isMobile) return; - - if (sidebarTimeoutRef.current) { - clearTimeout(sidebarTimeoutRef.current); - } - - if (isHovering) { - setSidebarOpen(true); - } else { - sidebarTimeoutRef.current = setTimeout(() => { - setSidebarOpen(false); - }, 300); // Small delay before closing - } - }; - - useEffect(() => { - if (ready && !authenticated) { - router.push('/'); - } - }, [ready, authenticated, router]); - - const handleLogout = useCallback(async () => { - try { - // Disconnect any connected wallets first - for (const wallet of wallets) { - try { - await wallet.disconnect(); - } catch (e) { - console.error('Error disconnecting wallet:', e); - } - } - - // Remove cookie before Privy logout to prevent race conditions - Cookies.remove('privy-authenticated', { path: '/' }); - - // Perform Privy logout - await privyLogout(); - - // Clear any local storage items - localStorage.removeItem('privy:embedded-wallet:iframe-ready'); - localStorage.removeItem('privy:embedded-wallet:ready'); - - // Redirect to auth page - router.push('/'); - } catch (error) { - console.error('Logout error:', error); - // Ensure redirect happens even if there's an error - router.push('/'); - } - }, [privyLogout, router, wallets]); - - // console.log("Cook: ",Cookies.get("privy-authenticated")) - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (!input.trim() || isLoading) return; - - const userMessage: Message = { - id: uuidv4(), - role: 'user', - content: input, - timestamp: new Date().toISOString() - }; - - setMessages(prev => [...prev, userMessage]); - setInput(''); - setIsLoading(true); - const timer = setTimeout(() => { - setIsLongResponse(true); - }, 10000); - scrollToBottom(); - - try { - const response = await fetch('/api/chat', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - message: input, - sessionId: sessionId, - }), - }); - - if (!response.ok) throw new Error('Failed to get response'); - - const data = await response.json(); - const messageContent = processResponse(data); - - const assistantMessage: Message = { - id: uuidv4(), - role: 'assistant', - content: messageContent, - timestamp: new Date().toISOString() - }; - - setMessages(prev => [...prev, assistantMessage]); - - if (!currentConversation) { - const newConversation: Conversation = { - id: sessionId, - title: input.slice(0, 30) + (input.length > 30 ? '...' : ''), - date: new Date().toLocaleDateString(), - messages: [userMessage, assistantMessage], - isStarred: false - }; - setConversations(prev => [newConversation, ...prev]); - setCurrentConversation(newConversation); - } - } catch (error) { - console.error('Error:', error); - setMessages(prev => [...prev, { - id: uuidv4(), - role: 'system', - content: 'Sorry, something went wrong. Please try again.', - timestamp: new Date().toISOString() - }]); - } finally { - setIsLoading(false); - setIsLongResponse(false); - clearTimeout(timer); - scrollToBottom(); - } - }; - - return ( - -
- {/* Always visible sidebar strip */} -
handleSidebarHover(true)} - onMouseLeave={() => handleSidebarHover(false)} - > - {/* Thin visible strip when sidebar is closed */} -
- - - {isSidebarOpen && ( - - - -
- {/* Starred Chats */} -
-

STARRED CHATS

-
- {conversations - .filter(chat => chat.isStarred) - .map(chat => ( - loadConversation(chat)} - onStar={() => handleStarChat(chat.id)} - /> - ))} -
-
- - {/* Regular Conversations */} -
-

CONVERSATIONS

-
- {conversations - .filter(chat => !chat.isStarred) - .map(chat => ( - loadConversation(chat)} - onStar={() => handleStarChat(chat.id)} - /> - ))} -
-
-
- - {/* User Section with Logout */} -
-
setShowLogout(true)} - onMouseLeave={() => setShowLogout(false)} - > -
-
- -
-
- {userName} - -
-
- {sessionId} -
-
-
-
- - - {showLogout && ( - - - Logout - - )} - -
- - -
-
- )} -
-
- - {/* Main Content Area with proper margin for sidebar strip */} -
- {/* Main Chat Area */} -
- {isMobile && ( - - )} - -
- {messages.length === 0 ? ( - <> - -

- Ready to help you with your tasks and questions. -

- -
- -
- - {/* Integration Buttons */} -
-

- EXPLORE INTEGRATIONS -

-
- {}} - /> - {}} - /> - {}} - /> - {}} - /> - {}} - /> -
-
- - ) : ( -
- {messages.map((message, i) => ( - - ))} - {isLoading && ( - - {/* Dots animation */} -
- - - -
- - {/* Processing message that appears after delay */} - {isLongResponse && ( - - - Hold on a moment... - - - )} -
-)} -
-
- -
-
- )} -
-
-
-
- - - ); -} - -// Helper function to process API response -function processResponse(data: { response: string; agent_responses?: { agent: string; response: string }[] }): string { -try { -const responseObj = JSON.parse(data.response); -let messageContent = ''; -const compassResponse = responseObj.agent_responses?.find( -(response: { agent: string }) => response.agent === "compass" -); - -if (compassResponse) { -messageContent = compassResponse.response; -} else { - -// Process Scout Response -const scoutResponse = responseObj.agent_responses?.find( -(response: { agent: string }) => response.agent === "scout" -); - -if (scoutResponse) { -try { -const researchData = JSON.parse(scoutResponse.response); -messageContent = researchData.message || scoutResponse.response; -} catch { -messageContent = scoutResponse.response; -} -messageContent = messageContent -.replace(/\b(bound)\b/gi, '**$1**') -.replace(/(bound)/gi, '**$1**'); -} - -// Process Tech Sage Response -const techSageResponse = responseObj.agent_responses?.find( -(response: { agent: string }) => response.agent === "techsage" -); - -if (techSageResponse) { -try { -const engineerData = JSON.parse(techSageResponse.response); -messageContent = formatEngineerResponse(engineerData); -} catch (parseError) { -console.error('Error parsing techsage response:', parseError); -messageContent = techSageResponse.response; -} -} -} -return messageContent || 'Received a response but couldn\'t process it properly.'; -} catch (error) { -console.error('Error processing response:', error); -return data.response; -} -} - -// Helper function to format engineer response -function formatEngineerResponse(engineerData: { status: string; message: string; suggestions?: string[]; query: string; analysis: { task_type: string; language: string; technologies: string[] }; implementation: { files: { filename: string; language: string; content: string }[]; setup?: string; usage?: string; api_docs?: string; configuration?: string }; files_created?: string[] }): string { -if (engineerData.status === "error") { -let content = `⚠️ Error: ${engineerData.message}\n\n`; -if (engineerData.suggestions?.length) { -content += "Suggestions:\n"; -engineerData.suggestions.forEach((suggestion: string) => { -content += `- ${suggestion}\n`; -}); -} -return content; -} - -let content = `# ${engineerData.query}\n\n`; - -content += `## Project Analysis\n`; -content += `- Type: ${engineerData.analysis.task_type}\n`; -content += `- Language: ${engineerData.analysis.language}\n`; -content += `- Technologies: ${engineerData.analysis.technologies.join(", ")}\n\n`; - -content += `## Implementation\n\n`; -engineerData.implementation.files.forEach((file: { filename: string; language: string; content: string }) => { -content += `### File: ${file.filename}\n`; -content += `\`\`\`${file.language}\n${file.content}\n\`\`\`\n\n`; -}); - -if (engineerData.implementation.setup) { -content += `## Setup Instructions\n${engineerData.implementation.setup}\n\n`; -} - -if (engineerData.implementation.usage) { -content += `## Usage Examples\n${engineerData.implementation.usage}\n\n`; -} - -if (engineerData.implementation.api_docs) { -content += `## API Documentation\n${engineerData.implementation.api_docs}\n\n`; -} - -if (engineerData.implementation.configuration) { -content += `## Configuration\n${engineerData.implementation.configuration}\n\n`; -} - -if (engineerData.files_created?.length) { -content += `## Files Created\n`; -engineerData.files_created.forEach((file: string) => { -content += `- \`${file}\`\n`; -}); -} - -return content; -} - -export default function Dashboard() { - return ( - - - - ); +'use client' + +import React, { useState, useEffect, useRef, useCallback } from 'react'; +import { v4 as uuidv4 } from 'uuid'; +import Cookies from 'js-cookie'; +import { usePrivy, useWallets } from '@privy-io/react-auth'; +import { useRouter } from 'next/navigation'; +import { Providers } from '@/components/providers/privy-provider'; +import { StarredChat } from '@/components/chat/sidebar/StarredChat'; +import { SidebarHeader } from '@/components/chat/sidebar/SidebarHeader'; +import { IntegrationButton } from '@/components/chat/IntegrationButton'; +import { ChatInput } from '@/components/chat/ChatInput'; +import { WelcomeHeader } from '@/components/chat/WelcomeHeader'; +import MessageBubble from '@/components/chat/MessageBubble'; +import { motion, AnimatePresence } from 'framer-motion'; +import { Settings, LogOut, Compass ,Landmark, Wrench, ScanSearch, Computer } from 'lucide-react'; +import Avatar, { genConfig } from 'react-nice-avatar'; +import logo from "@/public/assets/logo/landing-logo-blue.png" +import { NICKNAMES } from '@/components/chat/constants/nicknames'; + +interface Message { + id: string; + role: 'user' | 'assistant' | 'system'; + content: string; + timestamp: string; +} + +interface Conversation { + id: string; + title: string; + date: string; + messages: Message[]; + isStarred: boolean; +} + +function DashboardContent() { + const [conversations, setConversations] = useState([]); + const [messages, setMessages] = useState([]); + const [input, setInput] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [sessionId, setSessionId] = useState(() => uuidv4()); + const [currentConversation, setCurrentConversation] = useState(null); + const [isMobile, setIsMobile] = useState(false); + const [isSidebarOpen, setSidebarOpen] = useState(false); + const messagesEndRef = useRef(null); + const [showLogout, setShowLogout] = useState(false); + const [userName, setUserName] = useState('ALMAZE'); + const [avatarConfig, setAvatarConfig] = useState(() => genConfig()); + const { ready, authenticated, logout: privyLogout } = usePrivy(); + const router = useRouter(); + const { wallets } = useWallets(); + const sidebarTimeoutRef = useRef(); + const [isLongResponse, setIsLongResponse] = useState(false); + + //Random Username Generator + useEffect(() => { + const randomIndex = Math.floor(Math.random() * NICKNAMES.length); + const selectedName = NICKNAMES[randomIndex]; + setUserName(selectedName); + setAvatarConfig(genConfig(selectedName)); + }, []); + useEffect(() => { + const handleResize = () => { + const mobile = window.innerWidth <= 768; + setIsMobile(mobile); + setSidebarOpen(false); + }; + + handleResize(); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + + }, []); + + const scrollToBottom = useCallback(() => { + messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + }, []); + + const startNewChat = useCallback(() => { + const newSessionId = uuidv4(); + setSessionId(newSessionId); + setMessages([]); + setCurrentConversation(null); + setSidebarOpen(false); + // Force scroll to input + setTimeout(() => { + const inputElement = document.querySelector('input[type="text"]'); + (inputElement as HTMLInputElement)?.focus(); + }, 100); + }, [isMobile]); + + const handleStarChat = useCallback((id: string) => { + setConversations(prev => prev.map(conv => + conv.id === id ? { ...conv, isStarred: !conv.isStarred } : conv + )); + }, []); + + const loadConversation = useCallback((conversation: Conversation) => { + setSessionId(conversation.id); + setMessages(conversation.messages); + setCurrentConversation(conversation); + if (isMobile) setSidebarOpen(false); + }, [isMobile]); + + // Removed unused deleteConversation function + const handleSidebarHover = (isHovering: boolean) => { + if (isMobile) return; + + if (sidebarTimeoutRef.current) { + clearTimeout(sidebarTimeoutRef.current); + } + + if (isHovering) { + setSidebarOpen(true); + } else { + sidebarTimeoutRef.current = setTimeout(() => { + setSidebarOpen(false); + }, 300); // Small delay before closing + } + }; + + useEffect(() => { + if (ready && !authenticated) { + router.push('/'); + } + }, [ready, authenticated, router]); + + const handleLogout = useCallback(async () => { + try { + // Disconnect any connected wallets first + for (const wallet of wallets) { + try { + await wallet.disconnect(); + } catch (e) { + console.error('Error disconnecting wallet:', e); + } + } + + // Remove cookie before Privy logout to prevent race conditions + Cookies.remove('privy-authenticated', { path: '/' }); + + // Perform Privy logout + await privyLogout(); + + // Clear any local storage items + localStorage.removeItem('privy:embedded-wallet:iframe-ready'); + localStorage.removeItem('privy:embedded-wallet:ready'); + + // Redirect to auth page + router.push('/'); + } catch (error) { + console.error('Logout error:', error); + // Ensure redirect happens even if there's an error + router.push('/'); + } + }, [privyLogout, router, wallets]); + + // console.log("Cook: ",Cookies.get("privy-authenticated")) + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!input.trim() || isLoading) return; + + const userMessage: Message = { + id: uuidv4(), + role: 'user', + content: input, + timestamp: new Date().toISOString() + }; + + setMessages(prev => [...prev, userMessage]); + setInput(''); + setIsLoading(true); + const timer = setTimeout(() => { + setIsLongResponse(true); + }, 10000); + scrollToBottom(); + + try { + const response = await fetch('/api/chat', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + message: input, + sessionId: sessionId, + }), + }); + + if (!response.ok) throw new Error('Failed to get response'); + + const data = await response.json(); + const messageContent = processResponse(data); + + const assistantMessage: Message = { + id: uuidv4(), + role: 'assistant', + content: messageContent, + timestamp: new Date().toISOString() + }; + + setMessages(prev => [...prev, assistantMessage]); + + if (!currentConversation) { + const newConversation: Conversation = { + id: sessionId, + title: input.slice(0, 30) + (input.length > 30 ? '...' : ''), + date: new Date().toLocaleDateString(), + messages: [userMessage, assistantMessage], + isStarred: false + }; + setConversations(prev => [newConversation, ...prev]); + setCurrentConversation(newConversation); + } + } catch (error) { + console.error('Error:', error); + setMessages(prev => [...prev, { + id: uuidv4(), + role: 'system', + content: 'Sorry, something went wrong. Please try again.', + timestamp: new Date().toISOString() + }]); + } finally { + setIsLoading(false); + setIsLongResponse(false); + clearTimeout(timer); + scrollToBottom(); + } + }; + + return ( + +
+ {/* Always visible sidebar strip */} +
handleSidebarHover(true)} + onMouseLeave={() => handleSidebarHover(false)} + > + {/* Thin visible strip when sidebar is closed */} +
+ + + {isSidebarOpen && ( + + + +
+ {/* Starred Chats */} +
+

STARRED CHATS

+
+ {conversations + .filter(chat => chat.isStarred) + .map(chat => ( + loadConversation(chat)} + onStar={() => handleStarChat(chat.id)} + /> + ))} +
+
+ + {/* Regular Conversations */} +
+

CONVERSATIONS

+
+ {conversations + .filter(chat => !chat.isStarred) + .map(chat => ( + loadConversation(chat)} + onStar={() => handleStarChat(chat.id)} + /> + ))} +
+
+
+ + {/* User Section with Logout */} +
+
setShowLogout(true)} + onMouseLeave={() => setShowLogout(false)} + > +
+
+ +
+
+ {userName} + +
+
+ {sessionId} +
+
+
+
+ + + {showLogout && ( + + + Logout + + )} + +
+ + +
+
+ )} +
+
+ + {/* Main Content Area with proper margin for sidebar strip */} +
+ {/* Main Chat Area */} +
+ {isMobile && ( + + )} + +
+ {messages.length === 0 ? ( + <> + +

+ Ready to help you with your tasks and questions. +

+ +
+ +
+ + {/* Integration Buttons */} +
+

+ EXPLORE INTEGRATIONS +

+
+ setInput("How Almaze actually works?")} + /> + setInput("Help me design a learning path for becoming a full-stack developer")} + /> + setInput("What tools and resources would you recommend for learning data science?")} + /> + setInput("What are the latest trends in artificial intelligence and machine learning?")} + /> + setInput("Create an HTML/CSS template for a responsive portfolio website")} + /> +
+
+ + ) : ( +
+ {messages.map((message, i) => ( + + ))} + {isLoading && ( + + {/* Dots animation */} +
+ + + +
+ + {/* Processing message that appears after delay */} + {isLongResponse && ( + + + Hold on a moment... + + + )} +
+)} +
+
+ +
+
+ )} +
+
+
+
+ + + ); +} + +// Helper function to process API response +function processResponse(data: { response: string; agent_responses?: { agent: string; response: string }[] }): string { +try { +const responseObj = JSON.parse(data.response); +let messageContent = ''; +const compassResponse = responseObj.agent_responses?.find( +(response: { agent: string }) => response.agent === "compass" +); + +if (compassResponse) { +messageContent = compassResponse.response; +} else { + +// Process Scout Response +const scoutResponse = responseObj.agent_responses?.find( +(response: { agent: string }) => response.agent === "scout" +); + +if (scoutResponse) { +try { +const researchData = JSON.parse(scoutResponse.response); +messageContent = researchData.message || scoutResponse.response; +} catch { +messageContent = scoutResponse.response; +} +messageContent = messageContent +.replace(/\b(bound)\b/gi, '**$1**') +.replace(/(bound)/gi, '**$1**'); +} + +// Process Tech Sage Response +const techSageResponse = responseObj.agent_responses?.find( +(response: { agent: string }) => response.agent === "techsage" +); + +if (techSageResponse) { +try { +const engineerData = JSON.parse(techSageResponse.response); +messageContent = formatEngineerResponse(engineerData); +} catch (parseError) { +console.error('Error parsing techsage response:', parseError); +messageContent = techSageResponse.response; +} +} +} +return messageContent || 'Received a response but couldn\'t process it properly.'; +} catch (error) { +console.error('Error processing response:', error); +return data.response; +} +} + +// Helper function to format engineer response +function formatEngineerResponse(engineerData: { status: string; message: string; suggestions?: string[]; query: string; analysis: { task_type: string; language: string; technologies: string[] }; implementation: { files: { filename: string; language: string; content: string }[]; setup?: string; usage?: string; api_docs?: string; configuration?: string }; files_created?: string[] }): string { +if (engineerData.status === "error") { +let content = `⚠️ Error: ${engineerData.message}\n\n`; +if (engineerData.suggestions?.length) { +content += "Suggestions:\n"; +engineerData.suggestions.forEach((suggestion: string) => { +content += `- ${suggestion}\n`; +}); +} +return content; +} + +let content = `# ${engineerData.query}\n\n`; + +content += `## Project Analysis\n`; +content += `- Type: ${engineerData.analysis.task_type}\n`; +content += `- Language: ${engineerData.analysis.language}\n`; +content += `- Technologies: ${engineerData.analysis.technologies.join(", ")}\n\n`; + +content += `## Implementation\n\n`; +engineerData.implementation.files.forEach((file: { filename: string; language: string; content: string }) => { +content += `### File: ${file.filename}\n`; +content += `\`\`\`${file.language}\n${file.content}\n\`\`\`\n\n`; +}); + +if (engineerData.implementation.setup) { +content += `## Setup Instructions\n${engineerData.implementation.setup}\n\n`; +} + +if (engineerData.implementation.usage) { +content += `## Usage Examples\n${engineerData.implementation.usage}\n\n`; +} + +if (engineerData.implementation.api_docs) { +content += `## API Documentation\n${engineerData.implementation.api_docs}\n\n`; +} + +if (engineerData.implementation.configuration) { +content += `## Configuration\n${engineerData.implementation.configuration}\n\n`; +} + +if (engineerData.files_created?.length) { +content += `## Files Created\n`; +engineerData.files_created.forEach((file: string) => { +content += `- \`${file}\`\n`; +}); +} + +return content; +} + +export default function Dashboard() { + return ( + + + + ); } \ No newline at end of file