From d2ea0ff9cbfab5b735437c0da63c4b1cdd1402ad Mon Sep 17 00:00:00 2001 From: sumona-banerjeee Date: Fri, 17 Apr 2026 15:29:48 +0530 Subject: [PATCH] added the date time and proper conversation history --- src/app/chat/page.tsx | 675 ++++++++++++++++++++-------------- src/context/SocketContext.tsx | 84 ++--- src/lib/api.ts | 7 +- 3 files changed, 432 insertions(+), 334 deletions(-) diff --git a/src/app/chat/page.tsx b/src/app/chat/page.tsx index 560a3fb..c52546f 100644 --- a/src/app/chat/page.tsx +++ b/src/app/chat/page.tsx @@ -4,7 +4,7 @@ import { useState, useEffect, useRef, useMemo } from "react"; import { useRouter } from "next/navigation"; import { useAuth } from "@/context/AuthContext"; import { useSocket, type ChatMessage, type RoomNotice } from "@/context/SocketContext"; -import { fetchConversations, createConversation, fetchAllUsers, ConversationType, addParticipant, removeParticipant } from "@/lib/api"; +import { fetchConversations, createConversation, fetchAllUsers, ConversationType, addParticipant, removeParticipant, fetchMessages } from "@/lib/api"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { @@ -14,23 +14,12 @@ import { Plus, LogOut, Loader2, - Hash, - Wifi, - WifiOff, Users, User as UserIcon, UserMinus, UserPlus, + ChevronDown, } from "lucide-react"; -import { - Avatar, - AvatarFallback, - AvatarImage, -} from "@/components/ui/avatar"; -import { useDebounce } from "@/hooks/useDebounce"; - - - interface Room { id: string; @@ -39,7 +28,6 @@ interface Room { participants: { _id: string; name: string }[]; } - export default function ChatPage() { const router = useRouter(); const { user, isLoading: authLoading, logout } = useAuth(); @@ -56,21 +44,36 @@ export default function ChatPage() { setCurrentRoom, clearMessages, p2pReady, + setMessages, clearP2PReady, } = useSocket(); const [text, setText] = useState(""); const [roomSearch, setRoomSearch] = useState(""); const [userSearch, setUserSearch] = useState(""); - const [activeTab, setActiveTab] = useState<"rooms" | "users" | "create">("rooms"); + const [activeTab, setActiveTab] = useState<"rooms" | "users">("rooms"); + const [showCreateDropdown, setShowCreateDropdown] = useState(false); const [newRoomName, setNewRoomName] = useState(""); const [rooms, setRooms] = useState([]); const [allUsers, setAllUsers] = useState([]); + const [showManageDropdown, setShowManageDropdown] = useState(false); + + const messagesEndRef = useRef(null); + const dropdownRef = useRef(null); + const manageDropdownRef = useRef(null); + + // Debounce helper + const useDebounce = (value: string, delay: number) => { + const [debounced, setDebounced] = useState(value); + useEffect(() => { + const t = setTimeout(() => setDebounced(value), delay); + return () => clearTimeout(t); + }, [value, delay]); + return debounced; + }; const debouncedRoomSearch = useDebounce(roomSearch, 300); const debouncedUserSearch = useDebounce(userSearch, 300); - const messagesEndRef = useRef(null); - const [managingRoom, setManagingRoom] = useState(null); // Auth guard useEffect(() => { @@ -81,7 +84,6 @@ export default function ChatPage() { // Fetch rooms & Auto-join useEffect(() => { - // Guard: wait for everything needed if (!isConnected || !user?.userId || allUsers.length === 0) return; fetchConversations(user.userId) @@ -89,33 +91,22 @@ export default function ChatPage() { const loadedRooms = Array.isArray(data) ? data.map((c) => { const isGroup = c.type === "group"; - let roomName = c.name; - // FIX: derive name for P2P if (!isGroup) { let otherUserName = "Unknown User"; - - // Case 1: participants are objects if (typeof c.participants?.[0] === "object") { const otherUser = c.participants.find( (p: any) => p._id !== user.userId ); otherUserName = otherUser?.name || otherUserName; - } - // Case 2: participants are IDs - else { + } else { const otherUserId = c.participants?.find( (id: string) => id !== user.userId ); - - const otherUser = allUsers.find( - (u) => u._id === otherUserId - ); - + const otherUser = allUsers.find((u) => u._id === otherUserId); otherUserName = otherUser?.name || otherUserName; } - roomName = otherUserName; } @@ -130,7 +121,6 @@ export default function ChatPage() { setRooms(loadedRooms); - // Auto-join first room (only once) if (!currentRoom && loadedRooms.length > 0) { const firstRoom = loadedRooms[0]; setCurrentRoom(firstRoom.id); @@ -142,7 +132,40 @@ export default function ChatPage() { }); }, [isConnected, user, allUsers, currentRoom, joinRoom, setCurrentRoom]); - // Fetch all users for P2P tab + + + + + + useEffect(() => { + if (!currentRoom) return; + + fetchMessages(currentRoom) + .then((data) => { + const normalized = data.map((msg: any) => ({ + _id: msg._id, + roomId: msg.conversationId, + senderId: msg.senderId._id, + username: msg.senderId.name, + text: msg.text, + createdAt: msg.createdAt, + })); + + // Replace only this room's messages + setMessages((prev) => { + const others = prev.filter((m) => m.roomId !== currentRoom); + return [...others, ...normalized]; + }); + }) + .catch((err) => { + console.error("Failed to fetch messages:", err); + }); + }, [currentRoom, setMessages]); + + + + + // Fetch all users useEffect(() => { if (!user) return; fetchAllUsers() @@ -154,30 +177,52 @@ export default function ChatPage() { .catch(console.error); }, [user]); - // ── React to P2P Ready event + // React to P2P Ready event useEffect(() => { if (!p2pReady) return; - const targetUser = allUsers.find((u) => u._id === p2pReady.targetUserId); const roomName = targetUser?.name || "Direct Message"; - // Add the new P2P room to sidebar if not already there setRooms((prev) => { if (prev.find((r) => r.id === p2pReady.roomId)) return prev; - return [...prev, { id: p2pReady.roomId, name: roomName, isGroup: false }]; + return [ + ...prev, + { id: p2pReady.roomId, name: roomName, isGroup: false, participants: [] }, + ]; }); - // Switch to rooms tab setActiveTab("rooms"); clearP2PReady(); }, [p2pReady, allUsers, clearP2PReady]); - // ── Scroll to bottom on new messages + // Scroll to bottom on new messages useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages, notices]); - // ── Filtered rooms + // Close create dropdown on outside click + useEffect(() => { + const handleClickOutside = (e: MouseEvent) => { + if (!dropdownRef.current) return; + if (dropdownRef.current.contains(e.target as Node)) return; + setShowCreateDropdown(false); + }; + document.addEventListener("click", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + // Close manage dropdown on outside click + useEffect(() => { + const handleClickOutside = (e: MouseEvent) => { + if (!manageDropdownRef.current) return; + if (manageDropdownRef.current.contains(e.target as Node)) return; + setShowManageDropdown(false); + }; + document.addEventListener("click", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + // Filtered rooms const filteredRooms = useMemo(() => { if (!debouncedRoomSearch.trim()) return rooms; return rooms.filter((r) => @@ -185,7 +230,7 @@ export default function ChatPage() { ); }, [rooms, debouncedRoomSearch]); - // ── Messages for current room + // Messages for current room const roomMessages = useMemo( () => messages.filter((m) => m.roomId === currentRoom), [messages, currentRoom] @@ -196,17 +241,13 @@ export default function ChatPage() { [notices, currentRoom] ); - // ── Handlers + // Handlers const handleSelectRoom = (room: Room) => { if (currentRoom === room.id) return; - - // Leave old room - if (currentRoom) { - leaveRoom(currentRoom); - } - // Join new room + if (currentRoom) leaveRoom(currentRoom); setCurrentRoom(room.id); joinRoom(room.id); + setShowManageDropdown(false); }; const handleSend = () => { @@ -225,12 +266,11 @@ export default function ChatPage() { const handleCreateRoom = async () => { const name = newRoomName.trim(); if (!name) return; - console.log(user); try { const created = await createConversation({ name, type: ConversationType.GROUP, - participants: [user!.userId], // send userId not username + participants: [user!.userId], }); const newRoom: Room = { id: created._id || created.id, @@ -238,8 +278,11 @@ export default function ChatPage() { isGroup: true, participants: created.participants || [], }; - setRooms(prev => prev.find(r => r.id === newRoom.id) ? prev : [...prev, newRoom]); + setRooms((prev) => + prev.find((r) => r.id === newRoom.id) ? prev : [...prev, newRoom] + ); setNewRoomName(""); + setShowCreateDropdown(false); setActiveTab("rooms"); handleSelectRoom(newRoom); } catch (err) { @@ -247,17 +290,30 @@ export default function ChatPage() { } }; - const handleAddParticipant = async (convId: string, userId: string) => { try { const updated = await addParticipant(convId, userId); - setRooms(prev => prev.map(r => - r.id === convId - ? { ...r, participants: updated.participants || r.participants } - : r - )); - // refresh managingRoom state - setManagingRoom(prev => prev?.id === convId ? { ...prev, participants: updated.participants || prev.participants } : prev); + + // Normalize participants: if they're plain ID strings, hydrate with names from allUsers + const rawParticipants: any[] = updated.participants || []; + const hydrated = rawParticipants.map((p: any) => { + if (typeof p === "string") { + const found = allUsers.find((u) => u._id === p); + return found ? { _id: found._id, name: found.name } : { _id: p, name: p }; + } + // Already an object — but name might be missing, try to fill it in + if (!p.name) { + const found = allUsers.find((u) => u._id === (p._id ?? p)); + return found ? { _id: found._id, name: found.name } : p; + } + return p; + }); + + setRooms((prev) => + prev.map((r) => + r.id === convId ? { ...r, participants: hydrated } : r + ) + ); } catch (err: any) { console.error("Add participant failed:", err.message); } @@ -266,18 +322,53 @@ export default function ChatPage() { const handleRemoveParticipant = async (convId: string, userId: string) => { try { const updated = await removeParticipant(convId, userId); - setRooms(prev => prev.map(r => - r.id === convId - ? { ...r, participants: updated.participants || r.participants } - : r - )); - setManagingRoom(prev => prev?.id === convId ? { ...prev, participants: updated.participants || prev.participants } : prev); + + const rawParticipants: any[] = updated.participants || []; + const hydrated = rawParticipants.map((p: any) => { + if (typeof p === "string") { + const found = allUsers.find((u) => u._id === p); + return found ? { _id: found._id, name: found.name } : { _id: p, name: p }; + } + if (!p.name) { + const found = allUsers.find((u) => u._id === (p._id ?? p)); + return found ? { _id: found._id, name: found.name } : p; + } + return p; + }); + + setRooms((prev) => + prev.map((r) => + r.id === convId ? { ...r, participants: hydrated } : r + ) + ); } catch (err: any) { console.error("Remove participant failed:", err.message); } }; + const formatDate = (dateStr: string) => { + const date = new Date(dateStr); + const today = new Date(); + + const isToday = date.toDateString() === today.toDateString(); + if (isToday) return "Today"; + + return date.toLocaleDateString([], { + day: "numeric", + month: "short", + year: "numeric", + }); + }; + + const formatTime = (dateStr: string) => { + const date = new Date(dateStr); + return date.toLocaleTimeString([], { + hour: "2-digit", + minute: "2-digit", + }); + }; + const handleStartP2P = (targetUser: any) => { if (!targetUser?._id) return; startP2P(targetUser._id); @@ -289,7 +380,7 @@ export default function ChatPage() { logout(); }; - // ── Loading / Auth guard ────────────────────────────────────────── + // Loading / Auth guard if (authLoading || !user) { return (
@@ -300,6 +391,12 @@ export default function ChatPage() { const selectedRoom = rooms.find((r) => r.id === currentRoom); + // Participants for manage dropdown (current selected group room) + const manageParticipants = selectedRoom?.participants ?? []; + const addableUsers = allUsers.filter( + (u) => !manageParticipants.some((p: any) => (p._id ?? p) === u._id) + ); + return (
{/* ================= LEFT SIDEBAR ================= */} @@ -308,23 +405,44 @@ export default function ChatPage() {

Chats

- {/* Connection indicator */} - {isConnected ? ( - - ) : ( - - )}
+
- + {/* Create Group Dropdown */} +
+ + + {showCreateDropdown && ( +
+ setNewRoomName(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter") handleCreateRoom(); + }} + autoFocus + /> + +
+ )} +
+ + {/* Logout */}
- {/* TABS */} + {/* TABS — only Chats & People */}
-
- {/* CREATE ROOM PANEL */} - {activeTab === "create" && ( -
- setNewRoomName(e.target.value)} - className="rounded-full bg-muted" - onKeyDown={(e) => e.key === "Enter" && handleCreateRoom()} - /> - -
- )} - {/* ROOM LIST */} {activeTab === "rooms" && (
@@ -414,153 +503,43 @@ export default function ChatPage() { {filteredRooms.map((room) => { const isActive = currentRoom === room.id; - return ( -
+
handleSelectRoom(room)} + className={`flex items-center gap-3 p-3 rounded-xl cursor-pointer transition + ${isActive ? "bg-primary text-primary-foreground" : "hover:bg-muted"}`} + >
handleSelectRoom(room)} - className={`flex items-center gap-3 p-3 rounded-xl cursor-pointer transition flex-1 min-w-0 - ${isActive - ? "bg-primary text-primary-foreground" - : "hover:bg-muted" + className={`w-10 h-10 flex-shrink-0 flex items-center justify-center rounded-full ${isActive ? "bg-white/20" : "bg-primary/10" }`} > -
- {room.isGroup ? ( - - ) : ( - - )} -
- -
-

{room.name}

-

- {room.isGroup ? `${room.participants?.length ?? 0} members` : "Direct Message"} -

-
+ {room.isGroup ? ( + + ) : ( + + )} +
+
+

{room.name}

+

+ {room.isGroup + ? `${room.participants?.length ?? 0} members` + : "Direct Message"} +

- - {/* Manage button — group rooms only */} - {room.isGroup && ( - - )}
); })}
- - {/* ── Manage participants panel ── */} - {managingRoom && ( -
-
-

- {managingRoom.name} -

- -
- - {/* Current members */} -
-

- Members ({managingRoom.participants?.length ?? 0}) -

- {(managingRoom.participants ?? []).map((p: any) => { - const pid = p._id ?? p; - const pname = p.name ?? pid; - const isSelf = pid === user?.userId; - return ( -
-
-
- -
- - {pname} - {isSelf && ( - (you) - )} - -
- {!isSelf && ( - - )} -
- ); - })} -
- - {/* Add people */} - {(() => { - const addable = allUsers.filter( - (u) => - !(managingRoom.participants ?? []).some( - (p: any) => (p._id ?? p) === u._id - ) - ); - if (addable.length === 0) return null; - return ( -
-

- Add people -

- {addable.map((u) => ( -
-
-
- -
- {u.name} -
- -
- ))} -
- ); - })()} -
- )}
)} - {/* USERS / PEOPLE LIST (for starting P2P) */} + {/* PEOPLE LIST */} {activeTab === "users" && (
@@ -578,9 +557,12 @@ export default function ChatPage() {

) : ( allUsers - .filter((u) => - !debouncedUserSearch.trim() || - u.name?.toLowerCase().includes(debouncedUserSearch.toLowerCase()) + .filter( + (u) => + !debouncedUserSearch.trim() || + u.name + ?.toLowerCase() + .includes(debouncedUserSearch.toLowerCase()) ) .map((u) => (

{u.name}

-

Click to chat

+

+ Click to chat +

)) @@ -616,7 +600,9 @@ export default function ChatPage() { )}
- {selectedRoom?.name || "Select a room"} + + {selectedRoom?.name || "Select a room"} + {selectedRoom && (

{selectedRoom.isGroup @@ -628,7 +614,7 @@ export default function ChatPage() {

- {/* Call Buttons */} + {/* Right-side action buttons */}
+ + {/* Manage Participants — only for group rooms */} + {selectedRoom?.isGroup && ( +
+ + + {showManageDropdown && ( +
+

+ {selectedRoom.name} +

+ + {/* Current members */} +
+

+ Members ({manageParticipants.length}) +

+ {manageParticipants.map((p: any) => { + const pid = p._id ?? p; + const pname = p.name ?? pid; + const isSelf = pid === user?.userId; + return ( +
+
+
+ +
+ + {pname} + {isSelf && ( + + (you) + + )} + +
+ {!isSelf && ( + + )} +
+ ); + })} +
+ + {/* Add people */} + {addableUsers.length > 0 && ( +
+

+ Add people +

+ {addableUsers.map((u) => ( +
+
+
+ +
+ {u.name} +
+ +
+ ))} +
+ )} +
+ )} +
+ )}
@@ -655,35 +738,65 @@ export default function ChatPage() {
)} - {currentRoom && roomMessages.length === 0 && roomNotices.length === 0 && ( -
- No messages yet. Say something! -
- )} + {currentRoom && + roomMessages.length === 0 && + roomNotices.length === 0 && ( +
+ No messages yet. Say something! +
+ )} - {roomMessages.map((msg, idx) => { - const isMe = msg.senderId === mySocketId; - return ( -
-
- {!isMe && ( - - {msg.username} - + {(() => { + let lastDate = ""; + + return roomMessages.map((msg, idx) => { + const msgDate = formatDate(msg.createdAt!); + const showDate = msgDate !== lastDate; + lastDate = msgDate; + + const isMe = + msg.senderId === user?.userId || + msg.senderId === mySocketId; + + return ( +
+ {/* DATE SEPARATOR */} + {showDate && ( +
+ + {msgDate} + +
)} -
- {msg.text} + + {/* MESSAGE */} +
+
+ {!isMe && ( + + {msg.username} + + )} + +
+
{msg.text}
+ + {/* TIME */} +
+ {formatTime(msg.createdAt!)} +
+
+
-
- ); - })} + ); + }); + })()} {roomNotices.map((notice, idx) => (
@@ -703,7 +816,9 @@ export default function ChatPage() { onChange={(e) => setText(e.target.value)} onKeyDown={handleKeyDown} placeholder={ - currentRoom ? `Message ${selectedRoom?.name ?? ""}...` : "Select a room first..." + currentRoom + ? `Message ${selectedRoom?.name ?? ""}...` + : "Select a room first..." } disabled={!currentRoom || !isConnected} /> diff --git a/src/context/SocketContext.tsx b/src/context/SocketContext.tsx index fa64a98..23daf12 100644 --- a/src/context/SocketContext.tsx +++ b/src/context/SocketContext.tsx @@ -13,7 +13,9 @@ import { io, Socket } from "socket.io-client"; import { useAuth } from "./AuthContext"; import { API_BASE_URL } from "@/lib/api"; -// Shape of a chat message coming from the server +//types + +// Chat message export interface ChatMessage { _id?: string; roomId: string; @@ -23,76 +25,67 @@ export interface ChatMessage { createdAt?: string; } -// System messages related to a room (join/leave/info) +// System messages export interface RoomNotice { roomId: string; message: string; } -// Data received when a P2P room is ready +// P2P Ready export interface P2PReadyData { roomId: string; targetUserId: string; message: string; } -// Everything that the socket context will provide to the app +//context value + interface SocketContextValue { socket: Socket | null; isConnected: boolean; mySocketId: string | null; - // join / leave / send chat messages joinRoom: (roomId: string) => void; leaveRoom: (roomId: string) => void; sendMessage: (roomId: string, text: string) => void; startP2P: (targetUserId: string) => void; - // chat state stored globally messages: ChatMessage[]; + setMessages: React.Dispatch>; notices: RoomNotice[]; + currentRoom: string | null; setCurrentRoom: (roomId: string | null) => void; + clearMessages: () => void; - // P2P readiness (chat page reacts to this) p2pReady: P2PReadyData | null; clearP2PReady: () => void; } //context -// Create a global socket context + const SocketContext = createContext(undefined); -/* Provider */ +//provider export function SocketProvider({ children }: { children: ReactNode }) { const { user } = useAuth(); - // Keep socket instance in a ref so it persists without rerenders const socketRef = useRef(null); - // Connection status const [isConnected, setIsConnected] = useState(false); - - // Store current socket id assigned by server const [mySocketId, setMySocketId] = useState(null); - // All chat messages received const [messages, setMessages] = useState([]); - - // System notices (join/leave/info messages) const [notices, setNotices] = useState([]); - const [currentRoom, setCurrentRoom] = useState(null); - - // P2P ready event data — consumed by chat page const [p2pReady, setP2pReady] = useState(null); - // Connect to socket when user logs in, disconnect when logged out + //socket connection + useEffect(() => { if (!user?.token) { - // If user logs out, close socket connection if (socketRef.current) { socketRef.current.disconnect(); socketRef.current = null; @@ -102,10 +95,8 @@ export function SocketProvider({ children }: { children: ReactNode }) { return; } - // If already connected, don't reconnect again if (socketRef.current?.connected) return; - // Create socket connection with auth token const socket = io(`${API_BASE_URL}/chat`, { auth: { token: `Bearer ${user.token}` }, transports: ["websocket", "polling"], @@ -113,75 +104,73 @@ export function SocketProvider({ children }: { children: ReactNode }) { socketRef.current = socket; - /* ---------------- Server Events ---------------- */ + //connection events - // When connection is successfully established socket.on("connect", () => { setIsConnected(true); }); - // When server confirms who you are socket.on( "connected", (data: { YourId: string; username: string; message: string }) => { setMySocketId(data.YourId); console.log("[Socket] Connected:", data.message); - }, + } ); - // When socket disconnects socket.on("disconnect", () => { setIsConnected(false); setMySocketId(null); console.log("[Socket] Disconnected"); }); - // If authentication fails socket.on("authError", (data: { mesage?: string }) => { console.error("[Socket] Auth error:", data.mesage); socket.disconnect(); }); - // General server messages socket.on("serverNotice", (message: string) => { console.log("[Socket] Server notice:", message); }); - //- Room Events + //room event - // When you join a room socket.on("roomJoined", (data: { roomId: string; message: string }) => { console.log("[Socket] Room joined:", data.message); }); - // When you leave a room socket.on("roomLeft", (data: { roomId: string }) => { console.log("[Socket] Room left:", data.roomId); }); - // System messages inside a room socket.on("roomNotice", (data: RoomNotice) => { setNotices((prev) => [...prev, data]); }); - // P2P room ready — backend already did server-side join socket.on("p2pReady", (data: P2PReadyData) => { console.log("[Socket] P2P Ready:", data.message); setP2pReady(data); setCurrentRoom(data.roomId); }); - // New chat message received + //new message + socket.on("roomMessage", (data: ChatMessage) => { - setMessages((prev) => [...prev, data]); + setMessages((prev) => { + // Prevent duplicate messages + if (data._id && prev.find((m) => m._id === data._id)) { + return prev; + } + return [...prev, data]; + }); }); - // Room-related errors socket.on("roomError", (data: { message: string }) => { console.error("[Socket] Room error:", data.message); }); - // Cleanup socket when component unmounts or token changes + + return () => { socket.disconnect(); socketRef.current = null; @@ -190,40 +179,35 @@ export function SocketProvider({ children }: { children: ReactNode }) { }; }, [user?.token]); - // Actions you can call from UI + //actions - // Join a chat room const joinRoom = useCallback((roomId: string) => { socketRef.current?.emit("joinRoom", { roomId }); }, []); - // Leave a chat room const leaveRoom = useCallback((roomId: string) => { socketRef.current?.emit("leaveRoom", { roomId }); }, []); - // Send a message to a room const sendMessage = useCallback((roomId: string, text: string) => { socketRef.current?.emit("roomMessage", { roomId, text }); }, []); - // Start a P2P conversation via socket const startP2P = useCallback((targetUserId: string) => { - console.log(targetUserId); socketRef.current?.emit("startP2P", { targetUserId }); }, []); - // Clear all messages and notices const clearMessages = useCallback(() => { setMessages([]); setNotices([]); }, []); - // Clear p2pReady after chat page has consumed it const clearP2PReady = useCallback(() => { setP2pReady(null); }, []); + //provider + return ( "); return ctx; -} +} \ No newline at end of file diff --git a/src/lib/api.ts b/src/lib/api.ts index e111445..1915b7e 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -77,9 +77,8 @@ export async function removeParticipant(convId: string, userId: string): Promise return res.json(); } -export async function fetchMessages(roomId: string): Promise { - if (!roomId) return []; - const res = await fetch(`${API_BASE_URL}/messages?roomId=${roomId}`); - if (!res.ok) return []; +export async function fetchMessages(convId: string): Promise { + const res = await fetch(`${API_BASE_URL}/messages/${convId}`); + if (!res.ok) throw new Error("Failed to fetch messages"); return res.json(); } \ No newline at end of file