fix: message sending fallback + iOS zoom on input + openOrCreatePrivate
- MessageInput: HTTP fallback when WebSocket not OPEN (prevents silent failures) - WsClient: add trySend() returning bool to detect WS availability - Backend: POST /api/messages/chat/:chatId endpoint for HTTP message send - openOrCreatePrivate: use openChat() for consistency after refreshing chat list - iOS fix: inputs get font-size:16px on mobile to prevent Safari auto-zoom Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,14 @@ class WsClient {
|
||||
}
|
||||
}
|
||||
|
||||
trySend(type: string, payload: any): boolean {
|
||||
if (this.ws?.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(JSON.stringify({ type, payload }));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.token = null;
|
||||
if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
|
||||
|
||||
@@ -77,20 +77,29 @@ export default function MessageInput({ chatId, replyTo, editMsg, onCancelReply,
|
||||
if (textareaRef.current) textareaRef.current.style.height = 'auto';
|
||||
wsClient.send('typing', { chatId, typing: false });
|
||||
|
||||
if (editMsg) {
|
||||
wsClient.send('edit_message', { messageId: editMsg.id, content });
|
||||
onEditDone({ ...editMsg, content, isEdited: true });
|
||||
} else {
|
||||
wsClient.send('send_message', {
|
||||
chatId,
|
||||
content,
|
||||
type: 'text',
|
||||
replyToId: replyTo?.id || null,
|
||||
});
|
||||
onCancelReply();
|
||||
try {
|
||||
if (editMsg) {
|
||||
wsClient.send('edit_message', { messageId: editMsg.id, content });
|
||||
onEditDone({ ...editMsg, content, isEdited: true });
|
||||
} else {
|
||||
const sent = wsClient.trySend('send_message', {
|
||||
chatId, content, type: 'text', replyToId: replyTo?.id || null,
|
||||
});
|
||||
if (!sent) {
|
||||
// WS not available — use HTTP fallback
|
||||
const { data } = await api.post(`/api/messages/chat/${chatId}`, {
|
||||
content, type: 'text', replyToId: replyTo?.id || null,
|
||||
});
|
||||
addMessage(data);
|
||||
}
|
||||
onCancelReply();
|
||||
}
|
||||
} catch {
|
||||
// restore text so user doesn't lose it
|
||||
setText(content);
|
||||
} finally {
|
||||
setSending(false);
|
||||
}
|
||||
|
||||
setSending(false);
|
||||
}
|
||||
|
||||
async function handleFile(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
|
||||
@@ -35,3 +35,10 @@ body {
|
||||
/* Safe areas for mobile */
|
||||
.pb-safe { padding-bottom: env(safe-area-inset-bottom); }
|
||||
.pt-safe { padding-top: env(safe-area-inset-top); }
|
||||
|
||||
/* Prevent iOS auto-zoom on input focus (triggered when font-size < 16px) */
|
||||
@media screen and (max-width: 768px) {
|
||||
input, textarea, select {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,16 +90,19 @@ export default function MainLayout() {
|
||||
try {
|
||||
const { data: chatData } = await api.post(`/api/chats/private/${userId}`);
|
||||
setSearch('');
|
||||
// Load full chat detail directly by ID — don't rely on list lookup
|
||||
const { data: fullChatData } = await api.get(`/api/chats/${chatData.id}`);
|
||||
// Also refresh the sidebar chat list
|
||||
api.get('/api/chats').then(r => setChats(r.data)).catch(() => {});
|
||||
// Build chat object to open
|
||||
const chatToOpen = { ...fullChatData, id: chatData.id };
|
||||
setActiveChat(chatToOpen);
|
||||
setFullChat(chatToOpen);
|
||||
setMobileChatOpen(true);
|
||||
setShowInfo(false);
|
||||
const { data: allChats } = await api.get('/api/chats');
|
||||
setChats(allChats);
|
||||
const chatFromList = allChats.find((c: any) => c.id === chatData.id);
|
||||
if (chatFromList) {
|
||||
await openChat(chatFromList);
|
||||
} else {
|
||||
// fallback: open by direct API call
|
||||
const { data: fullChatData } = await api.get(`/api/chats/${chatData.id}`);
|
||||
setActiveChat(fullChatData);
|
||||
setFullChat(fullChatData);
|
||||
setMobileChatOpen(true);
|
||||
setShowInfo(false);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('openOrCreatePrivate:', e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user