Files
janichat/frontend/src/api/ws.ts
Ai 87c6d7f82f 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>
2026-05-22 12:44:42 +03:00

79 lines
2.1 KiB
TypeScript

type Handler = (payload: any) => void;
class WsClient {
private ws: WebSocket | null = null;
private handlers = new Map<string, Handler[]>();
private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
private token: string | null = null;
connect(token: string) {
this.token = token;
const wsBase = import.meta.env.VITE_WS_URL || `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}`;
this.ws = new WebSocket(`${wsBase}/ws?token=${token}`);
this.ws.onopen = () => {
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
this.emit('connected', null);
};
this.ws.onmessage = (event) => {
try {
const { type, payload } = JSON.parse(event.data);
const hs = this.handlers.get(type) || [];
hs.forEach(h => h(payload));
} catch {}
};
this.ws.onclose = () => {
this.emit('disconnected', null);
this.reconnectTimer = setTimeout(() => {
if (this.token) this.connect(this.token);
}, 3000);
};
this.ws.onerror = () => {
this.ws?.close();
};
}
on(type: string, handler: Handler) {
if (!this.handlers.has(type)) this.handlers.set(type, []);
this.handlers.get(type)!.push(handler);
return () => {
const hs = this.handlers.get(type) || [];
this.handlers.set(type, hs.filter(h => h !== handler));
};
}
private emit(type: string, payload: any) {
const hs = this.handlers.get(type) || [];
hs.forEach(h => h(payload));
}
send(type: string, payload: any) {
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type, payload }));
}
}
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);
this.ws?.close();
this.ws = null;
}
}
export const wsClient = new WsClient();