Добавлена поддержка входящих заявок в компоненты панели и мессенджера. Обновлены запросы GraphQL для получения данных о новых заявках, добавлены индикаторы для отображения количества входящих заявок в интерфейсе. Оптимизирован код для улучшения читаемости и взаимодействия с пользователем.
This commit is contained in:
@ -7,7 +7,7 @@ import { Card } from '@/components/ui/card'
|
||||
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'
|
||||
import { useRouter, usePathname } from 'next/navigation'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import { GET_CONVERSATIONS } from '@/graphql/queries'
|
||||
import { GET_CONVERSATIONS, GET_INCOMING_REQUESTS } from '@/graphql/queries'
|
||||
import {
|
||||
Settings,
|
||||
LogOut,
|
||||
@ -36,8 +36,18 @@ export function Sidebar() {
|
||||
notifyOnNetworkStatusChange: false, // Плавные обновления без мерцания
|
||||
})
|
||||
|
||||
// Загружаем входящие заявки для подсчета новых запросов
|
||||
const { data: incomingRequestsData } = useQuery(GET_INCOMING_REQUESTS, {
|
||||
pollInterval: 60000, // Обновляем каждую минуту
|
||||
fetchPolicy: 'cache-first',
|
||||
errorPolicy: 'ignore',
|
||||
notifyOnNetworkStatusChange: false,
|
||||
})
|
||||
|
||||
const conversations = conversationsData?.conversations || []
|
||||
const incomingRequests = incomingRequestsData?.incomingRequests || []
|
||||
const totalUnreadCount = conversations.reduce((sum: number, conv: { unreadCount?: number }) => sum + (conv.unreadCount || 0), 0)
|
||||
const incomingRequestsCount = incomingRequests.length
|
||||
|
||||
const getInitials = () => {
|
||||
const orgName = getOrganizationName()
|
||||
@ -258,7 +268,7 @@ export function Sidebar() {
|
||||
|
||||
<Button
|
||||
variant={isPartnersActive ? "secondary" : "ghost"}
|
||||
className={`w-full ${isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'} text-left transition-all duration-200 text-xs ${
|
||||
className={`w-full ${isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'} text-left transition-all duration-200 text-xs relative ${
|
||||
isPartnersActive
|
||||
? 'bg-white/20 text-white hover:bg-white/30'
|
||||
: 'text-white/80 hover:bg-white/10 hover:text-white'
|
||||
@ -268,6 +278,16 @@ export function Sidebar() {
|
||||
>
|
||||
<Handshake className="h-4 w-4 flex-shrink-0" />
|
||||
{!isCollapsed && <span className="ml-3">Партнёры</span>}
|
||||
{/* Индикатор входящих заявок */}
|
||||
{incomingRequestsCount > 0 && (
|
||||
<div className={`absolute ${
|
||||
isCollapsed
|
||||
? 'top-1 right-1 w-3 h-3'
|
||||
: 'top-2 right-2 w-4 h-4'
|
||||
} bg-red-500 text-white text-xs rounded-full flex items-center justify-center font-bold`}>
|
||||
{isCollapsed ? '' : (incomingRequestsCount > 99 ? '99+' : incomingRequestsCount)}
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
{/* Услуги - только для фулфилмент центров */}
|
||||
|
@ -167,9 +167,12 @@ export function MarketCounterparties() {
|
||||
<Users className="h-4 w-4 mr-2" />
|
||||
Контрагенты ({counterparties.length})
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="incoming" className="data-[state=active]:bg-green-500/20 data-[state=active]:text-green-300">
|
||||
<TabsTrigger value="incoming" className={`data-[state=active]:bg-green-500/20 data-[state=active]:text-green-300 relative ${incomingRequests.length > 0 ? 'ring-2 ring-green-400/50 animate-pulse' : ''}`}>
|
||||
<ArrowDownCircle className="h-4 w-4 mr-2" />
|
||||
Входящие ({incomingRequests.length})
|
||||
{incomingRequests.length > 0 && (
|
||||
<div className="absolute -top-1 -right-1 w-3 h-3 bg-green-500 rounded-full"></div>
|
||||
)}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="outgoing" className="data-[state=active]:bg-orange-500/20 data-[state=active]:text-orange-300">
|
||||
<ArrowUpCircle className="h-4 w-4 mr-2" />
|
||||
|
@ -338,17 +338,17 @@ export function MessengerChat({ counterparty, onMessagesRead }: MessengerChatPro
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div>
|
||||
<h3 className="font-semibold text-white">
|
||||
{getOrganizationName(counterparty)}
|
||||
</h3>
|
||||
<div className="flex items-center space-x-2">
|
||||
<h3 className="font-semibold text-white">
|
||||
{getOrganizationName(counterparty)}
|
||||
</h3>
|
||||
<Badge className={`${getTypeColor(counterparty.type)} text-xs`}>
|
||||
{getTypeLabel(counterparty.type)}
|
||||
</Badge>
|
||||
<p className="text-white/60 text-xs">
|
||||
{getShortCompanyName(counterparty.fullName || '')}
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-white/60 text-xs">
|
||||
{getShortCompanyName(counterparty.fullName || '')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -4,6 +4,8 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Sidebar } from '@/components/dashboard/sidebar'
|
||||
import { useSidebar } from '@/hooks/useSidebar'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import { GET_INCOMING_REQUESTS } from '@/graphql/queries'
|
||||
import { MarketCounterparties } from '../market/market-counterparties'
|
||||
import { MarketFulfillment } from '../market/market-fulfillment'
|
||||
import { MarketSellers } from '../market/market-sellers'
|
||||
@ -12,6 +14,17 @@ import { MarketWholesale } from '../market/market-wholesale'
|
||||
|
||||
export function PartnersDashboard() {
|
||||
const { getSidebarMargin } = useSidebar()
|
||||
|
||||
// Загружаем входящие заявки для подсветки
|
||||
const { data: incomingRequestsData } = useQuery(GET_INCOMING_REQUESTS, {
|
||||
pollInterval: 30000, // Обновляем каждые 30 секунд
|
||||
fetchPolicy: 'cache-first',
|
||||
errorPolicy: 'ignore',
|
||||
})
|
||||
|
||||
const incomingRequests = incomingRequestsData?.incomingRequests || []
|
||||
const hasIncomingRequests = incomingRequests.length > 0
|
||||
|
||||
return (
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
<Sidebar />
|
||||
@ -20,12 +33,15 @@ export function PartnersDashboard() {
|
||||
{/* Основной контент с табами */}
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<Tabs defaultValue="counterparties" className="h-full flex flex-col">
|
||||
<TabsList className="grid w-full grid-cols-5 bg-white/5 backdrop-blur border-white/10 flex-shrink-0">
|
||||
<TabsList className={`grid w-full grid-cols-5 bg-white/5 backdrop-blur border-white/10 flex-shrink-0 ${hasIncomingRequests ? 'ring-2 ring-blue-400/50' : ''}`}>
|
||||
<TabsTrigger
|
||||
value="counterparties"
|
||||
className="data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70"
|
||||
className={`data-[state=active]:bg-white/20 data-[state=active]:text-white text-white/70 relative ${hasIncomingRequests ? 'animate-pulse' : ''}`}
|
||||
>
|
||||
Мои контрагенты
|
||||
{hasIncomingRequests && (
|
||||
<div className="absolute -top-1 -right-1 w-3 h-3 bg-blue-500 rounded-full"></div>
|
||||
)}
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="fulfillment"
|
||||
|
Reference in New Issue
Block a user