diff --git a/services/dashboard/src/components/common/ContentContainerCard.tsx b/services/dashboard/src/components/common/ContentContainerCard.tsx index 17c0315..4c80d4c 100644 --- a/services/dashboard/src/components/common/ContentContainerCard.tsx +++ b/services/dashboard/src/components/common/ContentContainerCard.tsx @@ -8,6 +8,7 @@ interface ContentProps { interface RootProps { children: React.ReactNode; + className?: string; } interface FooterProps { @@ -17,9 +18,9 @@ interface HeaderProps { children: React.ReactNode; } -function Root({ children }: RootProps) { +function Root({ children, className }: RootProps) { return ( -
+
{children}
); diff --git a/services/dashboard/src/pages/Investigation/InvestigationDetails.tsx b/services/dashboard/src/pages/Investigation/InvestigationDetails.tsx index dd8eb7d..c54cfa4 100644 --- a/services/dashboard/src/pages/Investigation/InvestigationDetails.tsx +++ b/services/dashboard/src/pages/Investigation/InvestigationDetails.tsx @@ -9,6 +9,7 @@ import { IntegrationDetailsEvidenceChain, InvestigationDetailsHeader, InvestigationDetailsVerdict, + ChatWidget, } from "./components"; function InvestigationDetails() { @@ -41,17 +42,20 @@ function InvestigationDetails() { } return ( -
+
-
- {/* Added a large mb so that the last card have a bottom space to breath */} -
- +
+
+
+ +
+
+ +
+
+
- {/*
- Right sidebar components here -
*/}
); diff --git a/services/dashboard/src/pages/Investigation/components/ChatWidget.tsx b/services/dashboard/src/pages/Investigation/components/ChatWidget.tsx new file mode 100644 index 0000000..7025e97 --- /dev/null +++ b/services/dashboard/src/pages/Investigation/components/ChatWidget.tsx @@ -0,0 +1,245 @@ +import { Button } from "@/components/base/buttons/button"; +import Typography from "@/components/common/Typography"; +import { Tooltip, TooltipTrigger } from "@/components/base/tooltip/tooltip"; +import { Edit01, ClockRewind, XClose, ArrowCircleUp } from "@untitledui/icons"; +import { useState, useRef, useEffect } from "react"; +import logoCat from "@/assets/logo-cat.png"; +import { cx } from "@/utils/cx"; +import { motion, AnimatePresence } from "motion/react"; + +interface Message { + id: string; + role: "assistant" | "user"; + content: string; + timestamp: string; +} + +function getFormattedTimestamp() { + return new Intl.DateTimeFormat("en-US", { + day: "numeric", + month: "short", + year: "numeric", + hour: "numeric", + minute: "numeric", + hour12: true, + }).format(new Date()); +} + +const INITIAL_MESSAGES: Message[] = [ + { + id: "1", + role: "assistant", + content: "How can I help you today?", + timestamp: getFormattedTimestamp(), + }, +]; + +export function ChatWidget() { + const [messages, setMessages] = useState(INITIAL_MESSAGES); + const [inputValue, setInputValue] = useState(""); + const [isCollapsed, setIsCollapsed] = useState(false); + const messagesEndRef = useRef(null); + const textareaRef = useRef(null); + + useEffect(() => { + if (!isCollapsed) { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + } + }, [messages, isCollapsed]); + + function handleSend() { + const trimmed = inputValue.trim(); + if (!trimmed) return; + + setMessages((prev) => [ + ...prev, + { + id: Date.now().toString(), + role: "user", + content: trimmed, + timestamp: getFormattedTimestamp(), + }, + ]); + setInputValue(""); + if (textareaRef.current) { + textareaRef.current.style.height = "auto"; + } + } + + function handleKeyDown(e: React.KeyboardEvent) { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + handleSend(); + } + } + + function handleTextareaChange(e: React.ChangeEvent) { + setInputValue(e.target.value); + // Auto-resize + const el = e.target; + el.style.height = "auto"; + el.style.height = `${el.scrollHeight}px`; + } + + function handleNewChat() { + setMessages(INITIAL_MESSAGES); + setInputValue(""); + } + + return ( +
+ isCollapsed && setIsCollapsed(false)} + > + {/* Collapsed Logo - only visible when collapsed */} + + {isCollapsed && ( + + Aster Logo + + )} + + + {/* Expanded Content - Fades out when collapsed */} + + {/* Header */} +
+
+ +
+ +
+
+ Aster Logo + + CHAT + +
+
+ +
+ +
+
+ + {/* Messages */} +
+ {messages.map((msg) => ( + + ))} +
+
+ + {/* Input area */} +
+
+