Files
sfera/src/components/messenger/messenger-dashboard.tsx

150 lines
6.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import React, { useState } from 'react'
import { useQuery } from '@apollo/client'
import { Card } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Sidebar } from '@/components/dashboard/sidebar'
import { useSidebar } from '@/hooks/useSidebar'
import { MessengerConversations } from './messenger-conversations'
import { MessengerChatWithAttachments } from './messenger-chat-with-attachments'
import { MessengerEmptyState } from './messenger-empty-state'
import { GET_CONVERSATIONS, GET_MY_COUNTERPARTIES } from '@/graphql/queries'
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'
import { MessageCircle } from 'lucide-react'
interface Organization {
id: string
inn: string
name?: string
fullName?: string
type: 'FULFILLMENT' | 'SELLER' | 'LOGIST' | 'WHOLESALE'
address?: string
phones?: Array<{ value: string }>
emails?: Array<{ value: string }>
users?: Array<{ id: string, avatar?: string }>
createdAt: string
}
interface Conversation {
id: string
counterparty: Organization
lastMessage?: {
id: string
content?: string
type?: string
senderId: string
isRead: boolean
createdAt: string
}
unreadCount: number
updatedAt: string
}
export function MessengerDashboard() {
const { getSidebarMargin } = useSidebar()
const [selectedCounterparty, setSelectedCounterparty] = useState<string | null>(null)
// Загружаем список чатов (conversations) для отображения непрочитанных сообщений
const { data: conversationsData, loading: conversationsLoading, refetch: refetchConversations } = useQuery(GET_CONVERSATIONS, {
pollInterval: 30000, // Обновляем каждые 30 секунд - реже, но достаточно
fetchPolicy: 'cache-first', // Приоритет кэшу для стабильности
notifyOnNetworkStatusChange: false, // Не показываем загрузку при фоновых обновлениях
})
// Также загружаем полный список контрагентов на случай, если с кем-то еще не общались
const { data: counterpartiesData, loading: counterpartiesLoading } = useQuery(GET_MY_COUNTERPARTIES)
const conversations: Conversation[] = conversationsData?.conversations || []
const counterparties = counterpartiesData?.myCounterparties || []
const handleSelectCounterparty = (counterpartyId: string) => {
setSelectedCounterparty(counterpartyId)
}
// Найти данные выбранного контрагента (сначала в чатах, потом в общем списке)
const selectedCounterpartyData = conversations.find((conv: Conversation) => conv.counterparty.id === selectedCounterparty)?.counterparty ||
counterparties.find((cp: Organization) => cp.id === selectedCounterparty)
// Если нет контрагентов, показываем заглушку
if (!counterpartiesLoading && !conversationsLoading && counterparties.length === 0) {
return (
<div className="h-screen flex overflow-hidden">
<Sidebar />
<main className={`flex-1 ${getSidebarMargin()} px-6 py-4 overflow-hidden transition-all duration-300`}>
<div className="h-full w-full flex flex-col">
<div className="flex-1 overflow-hidden">
<Card className="glass-card h-full overflow-hidden p-6">
<MessengerEmptyState />
</Card>
</div>
</div>
</main>
</div>
)
}
return (
<div className="h-screen flex overflow-hidden">
<Sidebar />
<main className={`flex-1 ${getSidebarMargin()} px-6 py-4 overflow-hidden transition-all duration-300`}>
<div className="h-full w-full flex flex-col">
{/* Основной контент */}
<div className="flex-1 overflow-hidden">
<PanelGroup direction="horizontal" className="h-full">
{/* Левая панель - список контрагентов */}
<Panel
defaultSize={30}
minSize={15}
maxSize={50}
className="pr-2"
>
<Card className="glass-card h-full overflow-hidden p-4">
<MessengerConversations
conversations={conversations}
counterparties={counterparties}
loading={counterpartiesLoading || conversationsLoading}
selectedCounterparty={selectedCounterparty}
onSelectCounterparty={handleSelectCounterparty}
onRefresh={refetchConversations}
compact={false}
/>
</Card>
</Panel>
{/* Разделитель для изменения размера */}
<PanelResizeHandle className="w-2 hover:bg-white/10 transition-colors relative group cursor-col-resize">
<div className="absolute inset-y-0 left-1/2 transform -translate-x-1/2 w-1 bg-white/10 group-hover:bg-white/20 transition-colors" />
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-1 h-8 bg-white/30 rounded-full opacity-0 group-hover:opacity-100 transition-opacity" />
</PanelResizeHandle>
{/* Правая панель - чат */}
<Panel defaultSize={70} className="pl-2">
<Card className="glass-card h-full overflow-hidden">
{selectedCounterparty && selectedCounterpartyData ? (
<MessengerChatWithAttachments
counterparty={selectedCounterpartyData}
onMessagesRead={refetchConversations}
/>
) : (
<div className="flex items-center justify-center h-full">
<div className="text-center">
<div className="w-16 h-16 bg-white/10 rounded-full flex items-center justify-center mx-auto mb-4">
<MessageCircle className="h-8 w-8 text-white/40" />
</div>
<p className="text-white/60 text-lg mb-2">Выберите контрагента</p>
<p className="text-white/40 text-sm">
Начните беседу с одним из ваших контрагентов
</p>
</div>
</div>
)}
</Card>
</Panel>
</PanelGroup>
</div>
</div>
</main>
</div>
)
}