From 5d3be2a62801ffe9356e0f5cfd1de6c55d18de4a Mon Sep 17 00:00:00 2001 From: Ai Date: Fri, 22 May 2026 12:22:32 +0300 Subject: [PATCH] fix: private chat creation and search in NewChatModal - Fix: onOpen now async, MainLayout fetches fresh chats before opening (was using stale closure, chat wasn't found after creation) - Fix: search null-safety in user list filter (displayName/username could be undefined) - Fix: search also matches by phone number Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/NewChatModal.tsx | 29 ++++++++++++------------ frontend/src/pages/MainLayout.tsx | 10 +++++--- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/NewChatModal.tsx b/frontend/src/components/NewChatModal.tsx index 959debb..ff4b032 100644 --- a/frontend/src/components/NewChatModal.tsx +++ b/frontend/src/components/NewChatModal.tsx @@ -1,12 +1,11 @@ import { useState, useEffect } from 'react'; import { X, Search, MessageCircle, Users, Radio } from 'lucide-react'; import api from '../api/client'; -import { useStore } from '../store'; import Avatar from './Avatar'; interface Props { onClose: () => void; - onOpen: (chatId: string) => void; + onOpen: (chatId: string) => Promise; } type Step = 'type' | 'user' | 'group'; @@ -19,16 +18,18 @@ export default function NewChatModal({ onClose, onOpen }: Props) { const [selected, setSelected] = useState([]); const [groupTitle, setGroupTitle] = useState(''); const [loading, setLoading] = useState(false); - const { setChats, chats } = useStore(); + useEffect(() => { api.get('/api/users').then(r => setUsers(r.data)); }, []); - const filtered = users.filter(u => - u.displayName.toLowerCase().includes(search.toLowerCase()) || - u.username.toLowerCase().includes(search.toLowerCase()) - ); + const filtered = !search.trim() ? users : users.filter(u => { + const q = search.toLowerCase(); + return (u.displayName || '').toLowerCase().includes(q) || + (u.username || '').toLowerCase().includes(q) || + (u.phone || '').includes(q); + }); function toggleSelect(id: string) { setSelected(s => s.includes(id) ? s.filter(x => x !== id) : [...s, id]); @@ -38,12 +39,10 @@ export default function NewChatModal({ onClose, onOpen }: Props) { setLoading(true); try { const { data } = await api.post(`/api/chats/private/${userId}`); - const { data: chat } = await api.get(`/api/chats/${data.id}`); - // Refresh chats - const { data: allChats } = await api.get('/api/chats'); - setChats(allChats); - onOpen(data.id); onClose(); + await onOpen(data.id); + } catch (e: any) { + console.error('createPrivate error', e); } finally { setLoading(false); } @@ -58,10 +57,10 @@ export default function NewChatModal({ onClose, onOpen }: Props) { title: groupTitle, memberIds: selected, }); - const { data: allChats } = await api.get('/api/chats'); - setChats(allChats); - onOpen(data.id); onClose(); + await onOpen(data.id); + } catch (e: any) { + console.error('createGroup error', e); } finally { setLoading(false); } diff --git a/frontend/src/pages/MainLayout.tsx b/frontend/src/pages/MainLayout.tsx index 832990e..4df7bfa 100644 --- a/frontend/src/pages/MainLayout.tsx +++ b/frontend/src/pages/MainLayout.tsx @@ -246,9 +246,13 @@ export default function MainLayout() { {/* Modals */} - {showNew && setShowNew(false)} onOpen={(id) => { - const chat = chats.find(c => c.id === id); - if (chat) openChat(chat); + {showNew && setShowNew(false)} onOpen={async (id) => { + try { + const { data: allChats } = await api.get('/api/chats'); + setChats(allChats); + const found = allChats.find((c: any) => c.id === id); + if (found) openChat(found); + } catch {} }} />} {showAdmin && setShowAdmin(false)} />} {showProfile && setShowProfile(false)} />}