From a7c630d50ae9145d49669c3bab6b5a4234cf59ce Mon Sep 17 00:00:00 2001 From: Akash Santra Date: Wed, 19 Aug 2026 23:23:24 +0530 Subject: [PATCH] Update chat header --- frontend/src/components/ChatHeader.jsx | 376 +++++++++++++++---------- 1 file changed, 224 insertions(+), 152 deletions(-) diff --git a/frontend/src/components/ChatHeader.jsx b/frontend/src/components/ChatHeader.jsx index a56f8439..df05a2d6 100644 --- a/frontend/src/components/ChatHeader.jsx +++ b/frontend/src/components/ChatHeader.jsx @@ -44,6 +44,7 @@ const ChatHeader = () => { const [openMenu, setOpenMenu] = useState(false); const [showSearch, setShowSearch] = useState(false); const menuRef = useRef(null); + const searchInputRef = useRef(null); useEffect(() => { const handleClickOutside = (e) => { @@ -55,14 +56,22 @@ const ChatHeader = () => { return () => document.removeEventListener("mousedown", handleClickOutside); }, []); + useEffect(() => { + if (showSearch) { + const timer = setTimeout(() => searchInputRef.current?.focus(), 150); + return () => clearTimeout(timer); + } + }, [showSearch]); + if (!selectedUser && !selectedGroup) return null; const isGroup = selectedChatType === "group"; const isAI = !isGroup && selectedUser?.isAI; const chatId = isGroup ? selectedGroup?._id : selectedUser?._id; + const isOnline = !isGroup && !isAI && onlineUsers.includes(selectedUser?._id); const typingUserIds = Object.keys(typingUsers).filter( - (id) => id !== authUser._id, + (id) => id !== authUser?._id ); let typingText = null; @@ -70,16 +79,13 @@ const ChatHeader = () => { typingText = !isGroup ? "typing..." : typingUserIds.length === 1 - ? "Someone is typing..." - : `${typingUserIds.length} people typing...`; + ? "Someone is typing..." + : `${typingUserIds.length} people typing...`; } const handleClearChat = () => { if (!chatId) return; - const ok = window.confirm( - "Clear chat for you? This action cannot be undone.", - ); - if (ok) { + if (window.confirm("Clear chat for you? This action cannot be undone.")) { clearChatForMe(chatId); setOpenMenu(false); } @@ -87,7 +93,6 @@ const ChatHeader = () => { const handleWallpaperChange = () => { if (!chatId) return; - const input = document.createElement("input"); input.type = "file"; input.accept = "image/*"; @@ -102,7 +107,6 @@ const ChatHeader = () => { }; reader.readAsDataURL(file); }; - input.click(); }; @@ -112,31 +116,96 @@ const ChatHeader = () => { setOpenMenu(false); }; + const handleCloseSearch = () => { + clearSearch(); + setShowSearch(false); + }; + return ( -
-
- {/* Added min-w-0 here to allow children to truncate */} -
-
- + )} +
+ + + Search + + + + + + + )} + + + {/* Header Content */} +
+ {/* User / Group Info */} +
+ - + -
+ {/* Avatar */} +
{isGroup ? ( selectedGroup?.avatar ? ( {selectedGroup.name} ) : ( -
- - {selectedGroup.name[0].toUpperCase()} +
+ + {selectedGroup?.name?.[0]?.toUpperCase() || "G"}
) @@ -144,68 +213,75 @@ const ChatHeader = () => {
{isGroup - {!isGroup && - !isAI && - onlineUsers.includes(selectedUser?._id) && ( - - )} + {/* Online Status Indicator */} + {isOnline && ( + + )} + {/* AI Pulsing Ring */} {isAI && isAILoading && ( - + )}
)}
+ {/* Title & Status */}
-
-

+
+

{isGroup - ? selectedGroup.name + ? selectedGroup?.name : isAI - ? "Meta AI" - : selectedUser.fullName} + ? "Meta AI" + : selectedUser?.fullName}

{isAI && ( - + + + AI + )}
-
+
{isAI && isAILoading ? ( - AI is thinking... + + Thinking... ) : typingText ? ( + + + + + {typingText} ) : ( @@ -213,17 +289,20 @@ const ChatHeader = () => { key="status" initial={{ opacity: 0 }} animate={{ opacity: 1 }} - className="text-[10px] sm:text-xs text-base-content/50 truncate block" + className="text-[11px] text-base-content/60 truncate tracking-wide" > {isGroup - ? `${selectedGroup.members?.length || 0} members` + ? `${selectedGroup?.members?.length || 0} members` : isAI - ? "Always Active" - : onlineUsers.includes(selectedUser?._id) - ? "Active now" - : selectedUser?.lastSeen - ? `Last seen ${new Date(selectedUser.lastSeen).toLocaleString()}` - : "Offline"} + ? "Always ready to help" + : isOnline + ? "Active now" + : selectedUser?.lastSeen + ? `Last seen ${new Date(selectedUser.lastSeen).toLocaleTimeString([], { + hour: "2-digit", + minute: "2-digit", + })}` + : "Offline"} )} @@ -231,174 +310,167 @@ const ChatHeader = () => {
-
-
+ {/* Action Buttons */} +
+
{isGroup ? ( <> -
- setShowMembers(true)}> - - - - - {showMembers && isGroup && ( - setShowMembers(false)} - /> - )} - -
- setShowMembers(true)} + title="Group info" + > + + + startGroupCall({ groupId: selectedGroup._id, callType: "voice", }) } + title="Audio call" > - - - + + startGroupCall({ groupId: selectedGroup._id, callType: "video", }) } + title="Video call" > - +
- {/*SEARCH */} -
- setShowSearch((s) => !s)}> - - - - {showSearch && ( -
- setSearchQuery(e.target.value)} - onKeyDown={(e) => e.key === "Enter" && runSearch()} - placeholder="Search messages…" - className="input input-sm w-full" - /> - -
- - -
-
- )} + setShowSearch(true)} + title="Search conversation" + > + +
+ {/* 3-Dot Dropdown Menu */}
- + {openMenu && ( - + +
+ + )}
- + +
+ + {/* Group Members Modal */} + + {showMembers && isGroup && ( + setShowMembers(false)} + /> + )} +

); }; -const IconBtn = ({ children, onClick }) => ( - + ); -export default ChatHeader; +export default ChatHeader; \ No newline at end of file