'use client'; import React from 'react'; import { useRouter, usePathname, useSearchParams } from 'next/navigation'; import { Box, Typography } from '@mui/material'; import { getConversations, getChatById } from '@/api/chat'; import type { Chat } from '@/api/chat'; import { ChatList } from '@/components/chat/ChatList'; import { ChatWindow } from '@/components/chat/ChatWindow'; import { usePresenceWebSocket } from '@/hooks/usePresenceWebSocket'; import { useAuth } from '@/contexts/AuthContext'; import { useNavBadgesRefresh } from '@/contexts/NavBadgesContext'; export default function ChatPage() { const { user } = useAuth(); const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); const uuidFromUrl = searchParams.get('uuid'); const [loading, setLoading] = React.useState(true); const [chats, setChats] = React.useState([]); const [selected, setSelected] = React.useState(null); const [error, setError] = React.useState(null); const [hasMore, setHasMore] = React.useState(false); const [page, setPage] = React.useState(1); const [loadingMore, setLoadingMore] = React.useState(false); usePresenceWebSocket({ enabled: true }); const refreshNavBadges = useNavBadgesRefresh(); // На странице чата не должно быть общего скролла (скроллим только панели внутри) React.useEffect(() => { const prevHtml = document.documentElement.style.overflow; const prevBody = document.body.style.overflow; document.documentElement.style.overflow = 'hidden'; document.body.style.overflow = 'hidden'; return () => { document.documentElement.style.overflow = prevHtml; document.body.style.overflow = prevBody; }; }, []); const normalizeChat = React.useCallback((c: any) => { const otherName = c?.other_participant?.full_name || [c?.other_participant?.first_name, c?.other_participant?.last_name].filter(Boolean).join(' ') || c?.participant_name || 'Чат'; const avatarUrl = c?.other_participant?.avatar_url || c?.other_participant?.avatar || null; const otherId = c?.other_participant?.id ?? null; const otherOnline = !!c?.other_participant?.is_online; const otherLast = c?.other_participant?.last_activity ?? null; const lastText = c?.last_message?.content || c?.last_message?.text || c?.last_message || ''; const unread = c?.my_participant?.unread_count ?? c?.unread_count ?? 0; return { id: c.id, uuid: c.uuid, participant_name: otherName, avatar_url: avatarUrl, other_user_id: otherId, other_is_online: otherOnline, other_last_activity: otherLast, last_message: lastText, unread_count: unread, created_at: c.created_at, }; }, []); React.useEffect(() => { (async () => { try { setLoading(true); setError(null); const resp = await getConversations({ page: 1, page_size: 30 }); const normalized = (resp.results || []).map((c: any) => normalizeChat(c)); setChats(normalized as any); setHasMore(!!(resp as any).next); setPage(1); } catch (e: any) { console.error('[ChatPage] Ошибка загрузки чатов:', e); const msg = e?.response?.data?.detail || e?.response?.data?.error || e?.message || 'Не удалось загрузить чаты'; setError(String(msg)); } finally { setLoading(false); } })(); }, [normalizeChat]); const restoredForUuidRef = React.useRef(null); // Восстановить выбранный чат из URL после загрузки списка (или по uuid) React.useEffect(() => { if (loading || error || !uuidFromUrl) return; if (restoredForUuidRef.current === uuidFromUrl) return; const found = chats.find((c) => (c as any).uuid === uuidFromUrl); if (found) { setSelected(found as Chat); restoredForUuidRef.current = uuidFromUrl; return; } (async () => { try { const c = await getChatById(uuidFromUrl); const normalized = normalizeChat(c) as any; setSelected(normalized as Chat); restoredForUuidRef.current = uuidFromUrl; } catch (e: any) { console.warn('[ChatPage] Чат по uuid из URL не найден:', uuidFromUrl, e); restoredForUuidRef.current = null; router.replace(pathname ?? '/chat'); } })(); }, [loading, error, uuidFromUrl, chats, normalizeChat, router, pathname]); React.useEffect(() => { if (!uuidFromUrl) restoredForUuidRef.current = null; }, [uuidFromUrl]); const handleSelectChat = React.useCallback( (c: Chat) => { setSelected(c); const u = (c as any).uuid; if (u) { const base = pathname ?? '/chat'; router.replace(`${base}?uuid=${encodeURIComponent(u)}`); } }, [router, pathname] ); const loadMore = React.useCallback(async () => { if (loadingMore || !hasMore) return; try { setLoadingMore(true); const next = page + 1; const resp = await getConversations({ page: next, page_size: 30 }); const normalized = (resp.results || []).map((c: any) => normalizeChat(c)); setChats((prev) => [...prev, ...(normalized as any)]); setHasMore(!!(resp as any).next); setPage(next); } catch (e: any) { console.error('[ChatPage] Ошибка загрузки чатов:', e); } finally { setLoadingMore(false); } }, [page, hasMore, loadingMore, normalizeChat]); const refreshChatListUnread = React.useCallback(async () => { try { const resp = await getConversations({ page: 1, page_size: 30 }); const fresh = (resp.results || []).map((c: any) => normalizeChat(c)) as Chat[]; const freshByUuid = new Map(fresh.map((c: any) => [(c as any).uuid, c])); setChats((prev) => prev.map((c: any) => { const updated = freshByUuid.get(c.uuid); return updated ? (updated as Chat) : c; }) ); await refreshNavBadges?.(); } catch { // ignore } }, [normalizeChat, refreshNavBadges]); return (
{loading ? ( Загрузка… ) : error ? ( {error} ) : ( )}
); }