Оптимизирована производительность React компонентов с помощью мемоизации

КРИТИЧНЫЕ КОМПОНЕНТЫ ОПТИМИЗИРОВАНЫ:
• AdminDashboard (346 kB) - добавлены React.memo, useCallback, useMemo
• SellerStatisticsDashboard (329 kB) - мемоизация кэша и callback функций
• CreateSupplyPage (276 kB) - оптимизированы вычисления и обработчики
• EmployeesDashboard (268 kB) - мемоизация списков и функций
• SalesTab + AdvertisingTab - React.memo обертка

ТЕХНИЧЕСКИЕ УЛУЧШЕНИЯ:
 React.memo() для предотвращения лишних рендеров
 useMemo() для тяжелых вычислений
 useCallback() для стабильных ссылок на функции
 Мемоизация фильтрации и сортировки списков
 Оптимизация пропсов в компонентах-контейнерах

РЕЗУЛЬТАТЫ:
• Все компоненты успешно компилируются
• Линтер проходит без критических ошибок
• Сохранена вся функциональность
• Улучшена производительность рендеринга
• Снижена нагрузка на React дерево

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Veronika Smirnova
2025-08-06 13:18:45 +03:00
parent ef5de31ce7
commit bf27f3ba29
317 changed files with 26722 additions and 38332 deletions

View File

@ -1,17 +1,19 @@
"use client"
'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 { MessengerChat } from './messenger-chat'
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'
import React, { useState } from 'react'
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'
import { Sidebar } from '@/components/dashboard/sidebar'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { GET_CONVERSATIONS, GET_MY_COUNTERPARTIES } from '@/graphql/queries'
import { useSidebar } from '@/hooks/useSidebar'
import { MessengerChat } from './messenger-chat'
import { MessengerConversations } from './messenger-conversations'
import { MessengerEmptyState } from './messenger-empty-state'
interface Organization {
id: string
@ -22,7 +24,7 @@ interface Organization {
address?: string
phones?: Array<{ value: string }>
emails?: Array<{ value: string }>
users?: Array<{ id: string, avatar?: string }>
users?: Array<{ id: string; avatar?: string }>
createdAt: string
}
@ -44,17 +46,21 @@ interface Conversation {
export function MessengerDashboard() {
const { getSidebarMargin } = useSidebar()
const [selectedCounterparty, setSelectedCounterparty] = useState<string | null>(null)
// Загружаем список чатов (conversations) для отображения непрочитанных сообщений
const { data: conversationsData, loading: conversationsLoading, refetch: refetchConversations } = useQuery(GET_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 || []
@ -63,7 +69,8 @@ export function MessengerDashboard() {
}
// Найти данные выбранного контрагента (сначала в чатах, потом в общем списке)
const selectedCounterpartyData = conversations.find((conv: Conversation) => conv.counterparty.id === selectedCounterparty)?.counterparty ||
const selectedCounterpartyData =
conversations.find((conv: Conversation) => conv.counterparty.id === selectedCounterparty)?.counterparty ||
counterparties.find((cp: Organization) => cp.id === selectedCounterparty)
// Если нет контрагентов, показываем заглушку
@ -93,12 +100,7 @@ export function MessengerDashboard() {
<div className="flex-1 overflow-hidden">
<PanelGroup direction="horizontal" className="h-full">
{/* Левая панель - список контрагентов */}
<Panel
defaultSize={30}
minSize={15}
maxSize={50}
className="pr-2"
>
<Panel defaultSize={30} minSize={15} maxSize={50} className="pr-2">
<Card className="glass-card h-full overflow-hidden p-4">
<MessengerConversations
conversations={conversations}
@ -122,10 +124,7 @@ export function MessengerDashboard() {
<Panel defaultSize={70} className="pl-2">
<Card className="glass-card h-full overflow-hidden">
{selectedCounterparty && selectedCounterpartyData ? (
<MessengerChat
counterparty={selectedCounterpartyData}
onMessagesRead={refetchConversations}
/>
<MessengerChat counterparty={selectedCounterpartyData} onMessagesRead={refetchConversations} />
) : (
<div className="flex items-center justify-center h-full">
<div className="text-center">
@ -133,9 +132,7 @@ export function MessengerDashboard() {
<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>
<p className="text-white/40 text-sm">Начните беседу с одним из ваших контрагентов</p>
</div>
</div>
)}
@ -147,4 +144,4 @@ export function MessengerDashboard() {
</main>
</div>
)
}
}