Commit Graph

13 Commits

Author SHA1 Message Date
Ai
20daa2ca2f fix: read receipts (single/double check), push notifications for all users
- Track when others read messages via messages_read WS event
- Show Check (single) for sent, CheckCheck (double) only when read
- Send push to all recipients, SW suppresses if app is focused

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 13:47:38 +03:00
Ai
86073c0549 fix: use connection.socket (ws.WebSocket) instead of Duplex stream for message handling
@fastify/websocket v8 passes Duplex stream as first arg, not ws.WebSocket directly.
socket.on('message') never fired because Duplex streams don't emit 'message' events.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 13:38:14 +03:00
Ai
21edd7f7a3 fix: make WS handler synchronous — async handler breaks socket.on('message') in @fastify/websocket v8
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 13:31:21 +03:00
Ai
71b961ac2b debug: log WS messages to diagnose send issue 2026-05-22 13:26:19 +03:00
Ai
210d4302e7 fix: check can_send_messages === false instead of !can_send_messages (null blocks messages)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 13:15:30 +03:00
Ai
0ee3ead826 fix: repeat subquery in ORDER BY instead of using alias (PostgreSQL doesn't resolve SELECT aliases inside COALESCE)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 13:10:42 +03:00
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
Ai
2a4b7d5abc fix: open private chat from sidebar search
- openOrCreatePrivate: load chat by ID directly (skip stale list lookup)
- GET /api/chats/🆔 resolve title/avatar/privateUserId for private chats
  (was returning null title, causing chat area to behave unexpectedly)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 12:32:06 +03:00
Ai
8e5c4cd67d feat: phone login, position badge, logout in profile, global search, admin chats
- Login: by phone number instead of username
- Position field: shown as badge next to name in members list, search, admin panel
- Logout: moved from sidebar to profile modal settings
- Sidebar search: global — shows matching users with one-click private chat
- Admin panel: new Чаты tab showing all chats with delete, position/phone in user form
- Backend: /api/admin/chats endpoint, position column migration, phone login support

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 12:17:46 +03:00
Ai
3f54dbf375 feat: avatar upload for profile/chats, fix session persistence on refresh
- Profile modal: upload/remove user avatar, edit name/bio/phone, change password
- Chat info panel: upload/remove chat photo (owner/admin only)
- Avatar component: render photo when available, fallback to initials
- Session fix: initialize Zustand store from localStorage to prevent redirect on refresh
- Backend: avatar upload endpoints for users and chats, migration adds avatar columns

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 11:55:11 +03:00
Ai
567e5fd14a fix: wrap top-level await in main() for CommonJS compatibility 2026-05-22 11:16:23 +03:00
Ai
f12f4a4b68 fix: TypeScript errors — declare authenticate, fix WebSocket types 2026-05-22 11:13:44 +03:00
Ai
1cabe9d04f feat: initial JaniChat messenger — PWA, WebSocket, admin panel 2026-05-22 11:06:43 +03:00