Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 40 additions & 29 deletions frontend/src/components/ChatInterface.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ const ChatInterface = () => {
}
};

const handleCreateNewChat = () => setIsCreatingNewChat(true);


const handleNewChatSubmit = (e) => {
e.preventDefault();
Expand Down Expand Up @@ -174,8 +174,18 @@ const ChatInterface = () => {
if (window.innerWidth < 768) setSidebarOpen(false);
};

const handleCreateNewChat = () => {
setIsCreatingNewChat(true);
// Don't close sidebar when creating new chat
};

useEffect(() => {
const handleClickOutside = (event) => {
// Don't close sidebar if clicking on form elements
if (event.target.closest('input') || event.target.closest('textarea') || event.target.closest('select') || event.target.closest('button')) {
return;
}

if (sidebarRef.current && !sidebarRef.current.contains(event.target)) {
if (window.innerWidth < 768 && sidebarOpen) {
setSidebarOpen(false);
Expand Down Expand Up @@ -237,7 +247,7 @@ const ChatInterface = () => {
<div className="sidebar-top"> <nav className="main-nav"> <button className="new-thread-btn" onClick={handleCreateNewChat} disabled={!isAuthenticated}> <Icon path={<path d="M12 5v14m-7-7h14" />} /> <span>New Chat</span> </button> </nav> </div>
<div className="library">
<div className="library-header"> <h3>History</h3> </div>
{isCreatingNewChat && (<div className="new-chat-form-container"> <form onSubmit={handleNewChatSubmit} className={`new-chat-form ${titleError ? "error" : ""}`}> <input type="text" placeholder="New chat title..." value={newChatTitle} onChange={handleTitleChange} onBlur={() => !newChatTitle && setIsCreatingNewChat(false)} autoFocus/> <button type="submit" className="submit-new-chat-btn" disabled={!!titleError}> <Icon path={titleError ? (<path d="M18 6L6 18M6 6l12 12" />) : (<path d="M20 6L9 17l-5-5" />)} /> </button> </form> {titleError && (<p className="title-error-warning">{titleError}</p>)} </div>)}
{isCreatingNewChat && (<div className="new-chat-form-container" onClick={(e) => e.stopPropagation()}> <form onSubmit={handleNewChatSubmit} className={`new-chat-form ${titleError ? "error" : ""}`} onClick={(e) => e.stopPropagation()}> <input type="text" placeholder="New chat title..." value={newChatTitle} onChange={handleTitleChange} onBlur={() => !newChatTitle && setIsCreatingNewChat(false)} onClick={(e) => e.stopPropagation()} autoFocus/> <button type="submit" className="submit-new-chat-btn" disabled={!!titleError} onClick={(e) => e.stopPropagation()}> <Icon path={titleError ? (<path d="M18 6L6 18M6 6l12 12" />) : (<path d="M20 6L9 17l-5-5" />)} /> </button> </form> {titleError && (<p className="title-error-warning">{titleError}</p>)} </div>)}
<ul> {isAuthenticated ? (chats.length > 0 ? (chats.map((item) => (<li key={item._id} className={item._id === activeChatId ? "active" : ""} > <a href="#" onClick={(e) => { e.preventDefault(); handleHistoryClick(item._id); }}> <span>{item.title}</span> </a> </li>))) : (<li> <a href="#" className="no-chats"> <span>No chats found</span> </a> </li>)) : (<li> <a href="#" className="no-chats"> <span>Login to see history</span> </a> </li>)} </ul>
</div>
<div className="sidebar-bottom"> <div className="user-profile"> <div className="user-info"> <Icon path={<> <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /> <circle cx="12" cy="7" r="4" /> </>} /> <span>{user?.fullName?.firstName || "Guest User"}</span> </div> <div className={`credits-container ${isCreditsVisible ? 'show-text' : ''} ${creditsLoading ? 'loading' : ''} ${credits === 0 ? 'zero-credits' : ''}`} onClick={handleCreditsClick} > <span>{creditsLoading ? <div className="loading-spinner"></div> : (isAuthenticated ? `Credits: ${credits}` : (isCreditsVisible ? 'Login First' : 'Credits: 0'))}</span> </div> </div> </div>
Expand Down Expand Up @@ -292,22 +302,23 @@ const ChatInterface = () => {
<>
<h2>Start Your First Chat</h2>
<p>Create your first chat to begin your conversation with Atomic.</p>
<div className="first-chat-form-container">
<form onSubmit={handleFirstChatSubmit} className={`first-chat-form ${titleError ? "error" : ""}`}>
<input
type="text"
placeholder="Untitled Chat"
value={newChatTitle}
onChange={handleTitleChange}
onBlur={() => !newChatTitle && setIsCreatingFirstChat(false)}
autoFocus
/>
<button type="submit" className="submit-first-chat-btn" disabled={!!titleError}>
<Icon path={titleError ? <path d="M18 6L6 18M6 6l12 12" /> : <path d="M20 6L9 17l-5-5" />} />
</button>
</form>
{titleError && <p className="title-error-warning">{titleError}</p>}
</div>
<div className="first-chat-form-container" onClick={(e) => e.stopPropagation()}>
<form onSubmit={handleFirstChatSubmit} className={`first-chat-form ${titleError ? "error" : ""}`} onClick={(e) => e.stopPropagation()}>
<input
type="text"
placeholder="Untitled Chat"
value={newChatTitle}
onChange={handleTitleChange}
onBlur={() => !newChatTitle && setIsCreatingFirstChat(false)}
onClick={(e) => e.stopPropagation()}
autoFocus
/>
<button type="submit" className="submit-first-chat-btn" disabled={!!titleError} onClick={(e) => e.stopPropagation()}>
<Icon path={titleError ? <path d="M18 6L6 18M6 6l12 12" /> : <path d="M20 6L9 17l-5-5" />} />
</button>
</form>
{titleError && <p className="title-error-warning">{titleError}</p>}
</div>
</>
) : (
<>
Expand All @@ -330,17 +341,17 @@ const ChatInterface = () => {
</div>
</section>

<section className="chat-input-area">
<form className="input-form" onSubmit={handleSendMessage}>
<div className="input-wrapper"> <textarea ref={textareaRef} rows="1" placeholder={!isAuthenticated ? "Login to chat" : (characterLoading ? "Changing character..." : (!activeChatId ? "Make chat first then send message" : "Ask anything..."))} value={inputValue} onChange={(e) => setInputValue(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleSendMessage(e); } }} disabled={characterLoading || !isAuthenticated || !activeChatId} /> </div>
<div className="input-footer">
<div className="input-footer-left"> <select name="model" value={character} className={`model-selector ${characterLoading ? 'loading' : ''}`} onChange={handleChangeCharacter} disabled={characterLoading || !isAuthenticated || !activeChatId}> <option value="jahnvi">Jahnvi</option> <option value="atomic">Atomic</option> <option value="chandni">Chandni</option>
<option value="bhaiya"> Harsh Bhaiya</option>
</select> <div className={`char-counter ${inputValue.length > MAX_PROMPT_CHARS ? "error" : ""}`} > {MAX_PROMPT_CHARS - inputValue.length} / 1400 </div> </div>
<div className="input-footer-right"> <button type="submit" className="send-button" disabled={!inputValue.trim() || inputValue.length > MAX_PROMPT_CHARS || !activeChatId || characterLoading || !isAuthenticated}> <Icon path={<> <line x1="12" y1="19" x2="12" y2="5" /> <polyline points="5 12 12 5 19 12" /> </>} /> </button> </div>
</div>
</form>
</section>
<section className="chat-input-area" onClick={(e) => e.stopPropagation()}>
<form className="input-form" onSubmit={handleSendMessage} onClick={(e) => e.stopPropagation()}>
<div className="input-wrapper"> <textarea ref={textareaRef} rows="1" placeholder={!isAuthenticated ? "Login to chat" : (characterLoading ? "Changing character..." : (!activeChatId ? "Make chat first then send message" : "Ask anything..."))} value={inputValue} onChange={(e) => setInputValue(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); handleSendMessage(e); } }} onClick={(e) => e.stopPropagation()} disabled={characterLoading || !isAuthenticated || !activeChatId} /> </div>
<div className="input-footer">
<div className="input-footer-left"> <select name="model" value={character} className={`model-selector ${characterLoading ? 'loading' : ''}`} onChange={handleChangeCharacter} onClick={(e) => e.stopPropagation()} disabled={characterLoading || !isAuthenticated || !activeChatId}> <option value="jahnvi">Jahnvi</option> <option value="atomic">Atomic</option> <option value="chandni">Chandni</option>
<option value="bhaiya"> Harsh Bhaiya</option>
</select> <div className={`char-counter ${inputValue.length > MAX_PROMPT_CHARS ? "error" : ""}`} > {MAX_PROMPT_CHARS - inputValue.length} / 1400 </div> </div>
<div className="input-footer-right"> <button type="submit" className="send-button" disabled={!inputValue.trim() || inputValue.length > MAX_PROMPT_CHARS || !activeChatId || characterLoading || !isAuthenticated} onClick={(e) => e.stopPropagation()}> <Icon path={<> <line x1="12" y1="19" x2="12" y2="5" /> <polyline points="5 12 12 5 19 12" /> </>} /> </button> </div>
</div>
</form>
</section>
</main>
</div>
);
Expand Down