From eeb9df4ccf0c183ec324b7eb0d68194a9f3fa4d3 Mon Sep 17 00:00:00 2001 From: "Samuele E. Locatelli" Date: Fri, 22 Aug 2025 17:28:28 +0000 Subject: [PATCH] Add datetime for chat --- frontend/src/AssistantMessage.jsx | 99 +++++++++++++++++++++++++- frontend/src/AssistantMessage.jsx.orig | 32 +++++++++ frontend/src/ChatWindow.jsx | 15 +++- frontend/src/UserMessage.jsx | 36 ++++++++-- 4 files changed, 173 insertions(+), 9 deletions(-) create mode 100644 frontend/src/AssistantMessage.jsx.orig diff --git a/frontend/src/AssistantMessage.jsx b/frontend/src/AssistantMessage.jsx index f1792b8..2ee7d9b 100644 --- a/frontend/src/AssistantMessage.jsx +++ b/frontend/src/AssistantMessage.jsx @@ -1,10 +1,11 @@ -import React from "react"; +// src/AssistantMessage.jsx +import React, { useState } from "react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import remarkMath from "remark-math"; import rehypeKatex from "rehype-katex"; -export default function AssistantMessage({ content, theme }) { +export default function AssistantMessage({ content, theme, timestamp }) { return (
( ), - th: (props) =>
+ th: (props) => , + code: CodeWithCopy }} > {content} + {timestamp && ( +
+ {formatDateTime(timestamp)} +
+ )} ); } +function CodeWithCopy({ inline, className = "", children, ...props }) { + const [copied, setCopied] = useState(false); + const codeText = String(children).replace(/\n$/, ""); + + // Only show copy button for fenced code with language + const isFencedBlock = !inline && /^language-/.test(className); + + if (!isFencedBlock) { + return ( + + {children} + + ); + } + + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(codeText); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + } catch (err) { + console.error("Copy failed", err); + } + }; + + return ( +
+
+        {codeText}
+      
+ + {copied && ( + + Copied! + + )} +
+ ); +} + +// Utility to format timestamp nicely +function formatDateTime(dateTime) { + try { + const date = new Date(dateTime); + return date.toLocaleString(undefined, { + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + second: "2-digit" + }); + } catch { + return dateTime; + } +} + diff --git a/frontend/src/AssistantMessage.jsx.orig b/frontend/src/AssistantMessage.jsx.orig new file mode 100644 index 0000000..9070abc --- /dev/null +++ b/frontend/src/AssistantMessage.jsx.orig @@ -0,0 +1,32 @@ +// src/AssistantMessage.jsx +import React from "react"; +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; +import remarkMath from "remark-math"; +import rehypeKatex from "rehype-katex"; + +export default function AssistantMessage({ content, theme }) { + return ( +
+
+ ( + + ), + th: (props) =>
+ }} + > + {content} + + + + ); +} + + diff --git a/frontend/src/ChatWindow.jsx b/frontend/src/ChatWindow.jsx index c36287a..1f7a2ea 100644 --- a/frontend/src/ChatWindow.jsx +++ b/frontend/src/ChatWindow.jsx @@ -1,3 +1,4 @@ +// ChatWindow.jsx import React, { useRef, useEffect } from "react"; import UserMessage from "./UserMessage"; import AssistantMessage from "./AssistantMessage"; @@ -13,9 +14,19 @@ export default function ChatWindow({ messages, loading, theme }) {
{messages.map((m, idx) => m.role === "user" ? ( - + ) : ( - + ) )} {loading && ( diff --git a/frontend/src/UserMessage.jsx b/frontend/src/UserMessage.jsx index 52a968e..28118cc 100644 --- a/frontend/src/UserMessage.jsx +++ b/frontend/src/UserMessage.jsx @@ -1,10 +1,9 @@ -// UserMessage.jsx +// src/UserMessage.jsx import React from "react"; -export default function UserMessage({ content, theme }) { +export default function UserMessage({ content, theme, timestamp }) { return ( - // This outer div aligns the *bubble* to the right -
+
+ {timestamp && ( +
+ {formatDateTime(timestamp)} +
+ )}
); } +// Same helper used in AssistantMessage +function formatDateTime(dateTime) { + try { + const date = new Date(dateTime); + return date.toLocaleString(undefined, { + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + second: "2-digit" + }); + } catch { + return dateTime; + } +} +