"use client"; import { useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Music, Code, Monitor, MessageSquare, Send, X, Loader2, Github, Tv, Gamepad2, Coffee, Headphones, Terminal, Sparkles, ExternalLink, Activity, Waves, Zap, } from "lucide-react"; interface ActivityData { activity: { type: | "coding" | "listening" | "watching" | "gaming" | "reading" | "running"; details: string; timestamp: string; project?: string; language?: string; repo?: string; link?: string; } | null; music: { isPlaying: boolean; track: string; artist: string; album?: string; platform: "spotify" | "apple"; progress?: number; albumArt?: string; spotifyUrl?: string; } | null; watching: { title: string; platform: "youtube" | "netflix" | "twitch"; type: "video" | "stream" | "movie" | "series"; } | null; gaming: { game: string; platform: "steam" | "playstation" | "xbox"; status: "playing" | "idle"; } | null; status: { mood: string; customMessage?: string; } | null; } // Matrix rain effect for coding const MatrixRain = () => { const chars = "01"; return (
{[...Array(15)].map((_, i) => ( {[...Array(20)].map((_, j) => (
{chars[Math.floor(Math.random() * chars.length)]}
))}
))}
); }; // Sound waves for music const SoundWaves = () => { return (
{[...Array(5)].map((_, i) => ( ))}
); }; // Running animation with smooth wavy motion const RunningAnimation = () => { return (
🏃
); }; // Gaming particles const GamingParticles = () => { return (
{[...Array(10)].map((_, i) => ( ))}
); }; // TV scan lines const TVScanLines = () => { return (
); }; const activityIcons = { coding: Terminal, listening: Headphones, watching: Tv, gaming: Gamepad2, reading: Coffee, running: Activity, }; const activityColors = { coding: { bg: "from-liquid-mint/20 to-liquid-sky/20", border: "border-liquid-mint/40", text: "text-liquid-mint", pulse: "bg-green-500", }, listening: { bg: "from-liquid-rose/20 to-liquid-coral/20", border: "border-liquid-rose/40", text: "text-liquid-rose", pulse: "bg-red-500", }, watching: { bg: "from-liquid-lavender/20 to-liquid-pink/20", border: "border-liquid-lavender/40", text: "text-liquid-lavender", pulse: "bg-purple-500", }, gaming: { bg: "from-liquid-peach/20 to-liquid-yellow/20", border: "border-liquid-peach/40", text: "text-liquid-peach", pulse: "bg-orange-500", }, reading: { bg: "from-liquid-teal/20 to-liquid-lime/20", border: "border-liquid-teal/40", text: "text-liquid-teal", pulse: "bg-teal-500", }, running: { bg: "from-liquid-lime/20 to-liquid-mint/20", border: "border-liquid-lime/40", text: "text-liquid-lime", pulse: "bg-lime-500", }, }; export const ActivityFeed = () => { const [data, setData] = useState(null); const [showChat, setShowChat] = useState(false); const [chatMessage, setChatMessage] = useState(""); const [isLoading, setIsLoading] = useState(false); const [chatHistory, setChatHistory] = useState< { role: "user" | "ai"; text: string; timestamp: number; }[] >([ { role: "ai", text: "Hi! I'm Dennis's AI assistant. Ask me anything about his work, skills, or projects! 🚀", timestamp: Date.now(), }, ]); useEffect(() => { const fetchData = async () => { try { const res = await fetch("/api/n8n/status"); if (res.ok) { const json = await res.json(); setData(json); } } catch (e) { if (process.env.NODE_ENV === 'development') { console.error("Failed to fetch activity", e); } } }; fetchData(); const interval = setInterval(fetchData, 30000); // Poll every 30s return () => clearInterval(interval); }, []); const handleSendMessage = async (e: React.FormEvent) => { e.preventDefault(); if (!chatMessage.trim() || isLoading) return; const userMsg = chatMessage; setChatHistory((prev) => [ ...prev, { role: "user", text: userMsg, timestamp: Date.now() }, ]); setChatMessage(""); setIsLoading(true); try { const response = await fetch("/api/n8n/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ message: userMsg }), }); if (response.ok) { const data = await response.json(); setChatHistory((prev) => [ ...prev, { role: "ai", text: data.reply, timestamp: Date.now() }, ]); } else { throw new Error("Chat API failed"); } } catch (error) { if (process.env.NODE_ENV === 'development') { console.error("Chat error:", error); } setChatHistory((prev) => [ ...prev, { role: "ai", text: "Sorry, I encountered an error. Please try again later.", timestamp: Date.now(), }, ]); } finally { setIsLoading(false); } }; const renderActivityBubble = () => { if (!data?.activity) return null; const { type, details, project, language, link } = data.activity; const Icon = activityIcons[type]; const colors = activityColors[type]; return ( {/* Background Animation based on activity type */} {type === "coding" && } {type === "running" && } {type === "gaming" && } {type === "watching" && }
{type}

{details}

{project && (

{project}

)} {language && ( {language} )} {link && ( View )}
); }; const renderMusicBubble = () => { if (!data?.music?.isPlaying) return null; const { track, artist, album, progress, albumArt, spotifyUrl } = data.music; return ( {/* Animated sound waves background */} {albumArt && ( {album )}
Now Playing

{track}

{artist}

{progress !== undefined && (
)} {spotifyUrl && ( Listen with me )}
); }; const renderStatusBubble = () => { if (!data?.status) return null; const { mood, customMessage } = data.status; return ( {mood}
{customMessage && (

{customMessage}

)}
); }; return (
{/* Chat Window */} {showChat && (
AI Assistant
{chatHistory.map((msg, i) => (
{msg.text}
))} {isLoading && (
Thinking...
)}
setChatMessage(e.target.value)} placeholder="Ask me anything..." disabled={isLoading} className="flex-1 bg-white border-2 border-stone-200 rounded-xl px-4 py-3 text-sm text-stone-900 placeholder:text-stone-400 focus:outline-none focus:ring-2 focus:ring-liquid-mint focus:border-transparent disabled:opacity-50 transition-all duration-300" />
)}
{/* Activity Bubbles */}
{renderActivityBubble()} {renderMusicBubble()} {renderStatusBubble()} {/* Chat Toggle Button with Notification Indicator */} setShowChat(!showChat)} className="relative bg-stone-900 text-white rounded-full p-4 shadow-xl hover:bg-stone-950 transition-all duration-500 ease-out" title="Ask me anything about Dennis" > {!showChat && ( )}
); };