Оптимизирована производительность 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,6 @@
"use client";
'use client'
import { useAuth } from "@/hooks/useAuth";
import { useSidebar } from "@/hooks/useSidebar";
import { Button } from "@/components/ui/button";
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,
GET_INCOMING_REQUESTS,
GET_PENDING_SUPPLIES_COUNT,
} from "@/graphql/queries";
import { useQuery } from '@apollo/client'
import {
Settings,
LogOut,
@ -27,252 +16,234 @@ import {
BarChart3,
Home,
DollarSign,
} from "lucide-react";
} from 'lucide-react'
import { useRouter, usePathname } from 'next/navigation'
// Компонент для отображения уведомлений о непринятых поставках
function PendingSuppliesNotification() {
const { data: pendingData } = useQuery(GET_PENDING_SUPPLIES_COUNT, {
pollInterval: 30000, // Обновляем каждые 30 секунд
fetchPolicy: "cache-first",
errorPolicy: "ignore",
});
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import { GET_CONVERSATIONS, GET_INCOMING_REQUESTS, GET_PENDING_SUPPLIES_COUNT } from '@/graphql/queries'
import { useAuth } from '@/hooks/useAuth'
import { useSidebar } from '@/hooks/useSidebar'
const pendingCount = pendingData?.pendingSuppliesCount?.total || 0;
if (pendingCount === 0) return null;
return (
<div className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full min-w-[18px] h-[18px] flex items-center justify-center font-bold animate-pulse">
{pendingCount > 99 ? "99+" : pendingCount}
</div>
);
}
// Компонент для отображения логистических заявок (только для логистики)
function LogisticsOrdersNotification() {
const { data: pendingData } = useQuery(GET_PENDING_SUPPLIES_COUNT, {
pollInterval: 30000, // Обновляем каждые 30 секунд
fetchPolicy: "cache-first",
errorPolicy: "ignore",
});
fetchPolicy: 'cache-first',
errorPolicy: 'ignore',
})
const logisticsCount =
pendingData?.pendingSuppliesCount?.logisticsOrders || 0;
const logisticsCount = pendingData?.pendingSuppliesCount?.logisticsOrders || 0
if (logisticsCount === 0) return null;
if (logisticsCount === 0) return null
return (
<div className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full min-w-[18px] h-[18px] flex items-center justify-center font-bold animate-pulse">
{logisticsCount > 99 ? "99+" : logisticsCount}
{logisticsCount > 99 ? '99+' : logisticsCount}
</div>
);
)
}
// Компонент для отображения поставок фулфилмента (только поставки, не заявки на партнерство)
function FulfillmentSuppliesNotification() {
const { data: pendingData } = useQuery(GET_PENDING_SUPPLIES_COUNT, {
pollInterval: 30000, // Обновляем каждые 30 секунд
fetchPolicy: "cache-first",
errorPolicy: "ignore",
});
fetchPolicy: 'cache-first',
errorPolicy: 'ignore',
})
const suppliesCount = pendingData?.pendingSuppliesCount?.supplyOrders || 0;
const suppliesCount = pendingData?.pendingSuppliesCount?.supplyOrders || 0
if (suppliesCount === 0) return null;
if (suppliesCount === 0) return null
return (
<div className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full min-w-[18px] h-[18px] flex items-center justify-center font-bold animate-pulse">
{suppliesCount > 99 ? "99+" : suppliesCount}
{suppliesCount > 99 ? '99+' : suppliesCount}
</div>
);
)
}
// Компонент для отображения входящих заказов поставщика (только входящие заказы, не заявки на партнерство)
function WholesaleOrdersNotification() {
const { data: pendingData } = useQuery(GET_PENDING_SUPPLIES_COUNT, {
pollInterval: 30000, // Обновляем каждые 30 секунд
fetchPolicy: "cache-first",
errorPolicy: "ignore",
});
fetchPolicy: 'cache-first',
errorPolicy: 'ignore',
})
const ordersCount =
pendingData?.pendingSuppliesCount?.incomingSupplierOrders || 0;
const ordersCount = pendingData?.pendingSuppliesCount?.incomingSupplierOrders || 0
if (ordersCount === 0) return null;
if (ordersCount === 0) return null
return (
<div className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full min-w-[18px] h-[18px] flex items-center justify-center font-bold animate-pulse">
{ordersCount > 99 ? "99+" : ordersCount}
{ordersCount > 99 ? '99+' : ordersCount}
</div>
);
)
}
export function Sidebar() {
const { user, logout } = useAuth();
const router = useRouter();
const pathname = usePathname();
const { isCollapsed, toggleSidebar } = useSidebar();
const { user, logout } = useAuth()
const router = useRouter()
const pathname = usePathname()
const { isCollapsed, toggleSidebar } = useSidebar()
// Загружаем список чатов для подсчета непрочитанных сообщений
const { data: conversationsData } = useQuery(GET_CONVERSATIONS, {
pollInterval: 60000, // Обновляем каждую минуту в сайдбаре - этого достаточно
fetchPolicy: "cache-first",
errorPolicy: "ignore", // Игнорируем ошибки чтобы не ломать сайдбар
fetchPolicy: 'cache-first',
errorPolicy: 'ignore', // Игнорируем ошибки чтобы не ломать сайдбар
notifyOnNetworkStatusChange: false, // Плавные обновления без мерцания
});
})
// Загружаем входящие заявки для подсчета новых запросов
const { data: incomingRequestsData } = useQuery(GET_INCOMING_REQUESTS, {
pollInterval: 60000, // Обновляем каждую минуту
fetchPolicy: "cache-first",
errorPolicy: "ignore",
fetchPolicy: 'cache-first',
errorPolicy: 'ignore',
notifyOnNetworkStatusChange: false,
});
})
const conversations = conversationsData?.conversations || [];
const incomingRequests = incomingRequestsData?.incomingRequests || [];
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;
(sum: number, conv: { unreadCount?: number }) => sum + (conv.unreadCount || 0),
0,
)
const incomingRequestsCount = incomingRequests.length
const getInitials = () => {
const orgName = getOrganizationName();
return orgName.charAt(0).toUpperCase();
};
const orgName = getOrganizationName()
return orgName.charAt(0).toUpperCase()
}
const getOrganizationName = () => {
if (user?.organization?.name) {
return user.organization.name;
return user.organization.name
}
if (user?.organization?.fullName) {
return user.organization.fullName;
return user.organization.fullName
}
return "Организация";
};
return 'Организация'
}
const getCabinetType = () => {
if (!user?.organization?.type) return "Кабинет";
if (!user?.organization?.type) return 'Кабинет'
switch (user.organization.type) {
case "FULFILLMENT":
return "Фулфилмент";
case "SELLER":
return "Селлер";
case "LOGIST":
return "Логистика";
case "WHOLESALE":
return "Поставщик";
case 'FULFILLMENT':
return 'Фулфилмент'
case 'SELLER':
return 'Селлер'
case 'LOGIST':
return 'Логистика'
case 'WHOLESALE':
return 'Поставщик'
default:
return "Кабинет";
return 'Кабинет'
}
};
}
const handleSettingsClick = () => {
router.push("/settings");
};
router.push('/settings')
}
const handleMarketClick = () => {
router.push("/market");
};
router.push('/market')
}
const handleMessengerClick = () => {
router.push("/messenger");
};
router.push('/messenger')
}
const handleServicesClick = () => {
router.push("/services");
};
router.push('/services')
}
const handleWarehouseClick = () => {
router.push("/warehouse");
};
router.push('/warehouse')
}
const handleWBWarehouseClick = () => {
router.push("/wb-warehouse");
};
router.push('/wb-warehouse')
}
const handleEmployeesClick = () => {
router.push("/employees");
};
router.push('/employees')
}
const handleSuppliesClick = () => {
// Для каждого типа кабинета свой роут
switch (user?.organization?.type) {
case "FULFILLMENT":
router.push("/fulfillment-supplies");
break;
case "SELLER":
router.push("/supplies");
break;
case "WHOLESALE":
router.push("/supplier-orders");
break;
case "LOGIST":
router.push("/logistics-orders");
break;
case 'FULFILLMENT':
router.push('/fulfillment-supplies')
break
case 'SELLER':
router.push('/supplies')
break
case 'WHOLESALE':
router.push('/supplier-orders')
break
case 'LOGIST':
router.push('/logistics-orders')
break
default:
router.push("/supplies");
router.push('/supplies')
}
};
}
const handleFulfillmentWarehouseClick = () => {
router.push("/fulfillment-warehouse");
};
router.push('/fulfillment-warehouse')
}
const handleFulfillmentStatisticsClick = () => {
router.push("/fulfillment-statistics");
};
router.push('/fulfillment-statistics')
}
const handleSellerStatisticsClick = () => {
router.push("/seller-statistics");
};
router.push('/seller-statistics')
}
const handlePartnersClick = () => {
router.push("/partners");
};
router.push('/partners')
}
const handleHomeClick = () => {
router.push("/home");
};
router.push('/home')
}
const handleEconomicsClick = () => {
router.push("/economics");
};
router.push('/economics')
}
const isHomeActive = pathname === "/home";
const isEconomicsActive = pathname === "/economics";
const isSettingsActive = pathname === "/settings";
const isMarketActive = pathname.startsWith("/market");
const isMessengerActive = pathname.startsWith("/messenger");
const isServicesActive = pathname.startsWith("/services");
const isWarehouseActive = pathname.startsWith("/warehouse");
const isWBWarehouseActive = pathname.startsWith("/wb-warehouse");
const isFulfillmentWarehouseActive = pathname.startsWith(
"/fulfillment-warehouse"
);
const isFulfillmentStatisticsActive = pathname.startsWith(
"/fulfillment-statistics"
);
const isSellerStatisticsActive = pathname.startsWith("/seller-statistics");
const isEmployeesActive = pathname.startsWith("/employees");
const isHomeActive = pathname === '/home'
const isEconomicsActive = pathname === '/economics'
const isSettingsActive = pathname === '/settings'
const isMarketActive = pathname.startsWith('/market')
const isMessengerActive = pathname.startsWith('/messenger')
const isServicesActive = pathname.startsWith('/services')
const isWarehouseActive = pathname.startsWith('/warehouse')
const isWBWarehouseActive = pathname.startsWith('/wb-warehouse')
const isFulfillmentWarehouseActive = pathname.startsWith('/fulfillment-warehouse')
const isFulfillmentStatisticsActive = pathname.startsWith('/fulfillment-statistics')
const isSellerStatisticsActive = pathname.startsWith('/seller-statistics')
const isEmployeesActive = pathname.startsWith('/employees')
const isSuppliesActive =
pathname.startsWith("/supplies") ||
pathname.startsWith("/fulfillment-supplies") ||
pathname.startsWith("/logistics") ||
pathname.startsWith("/supplier-orders");
const isPartnersActive = pathname.startsWith("/partners");
pathname.startsWith('/supplies') ||
pathname.startsWith('/fulfillment-supplies') ||
pathname.startsWith('/logistics') ||
pathname.startsWith('/supplier-orders')
const isPartnersActive = pathname.startsWith('/partners')
return (
<div className="relative">
{/* Основной сайдбар */}
<div
className={`fixed left-4 top-4 bottom-4 ${
isCollapsed ? "w-16" : "w-56"
isCollapsed ? 'w-16' : 'w-56'
} bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl ${
isCollapsed ? "p-2" : "p-3"
isCollapsed ? 'p-2' : 'p-3'
} transition-all duration-300 ease-in-out z-50`}
>
{/* ОХУЕННАЯ кнопка сворачивания - на правом краю сайдбара */}
@ -284,7 +255,7 @@ export function Sidebar() {
size="icon"
onClick={toggleSidebar}
className="relative h-12 w-12 rounded-full bg-gradient-to-br from-white/20 to-white/5 border border-white/30 hover:from-white/30 hover:to-white/10 transition-all duration-300 ease-out hover:scale-110 active:scale-95 backdrop-blur-xl shadow-lg hover:shadow-xl hover:shadow-purple-500/20 group-hover:border-purple-300/50"
title={isCollapsed ? "Развернуть сайдбар" : "Свернуть сайдбар"}
title={isCollapsed ? 'Развернуть сайдбар' : 'Свернуть сайдбар'}
>
{/* Простая анимированная иконка */}
<div className="transition-transform duration-300 ease-out group-hover:scale-110">
@ -322,11 +293,7 @@ export function Sidebar() {
<div className="relative flex-shrink-0">
<Avatar className="h-8 w-8 ring-2 ring-white/40">
{user?.avatar ? (
<AvatarImage
src={user.avatar}
alt="Аватар пользователя"
className="w-full h-full object-cover"
/>
<AvatarImage src={user.avatar} alt="Аватар пользователя" className="w-full h-full object-cover" />
) : null}
<AvatarFallback className="bg-gradient-to-br from-purple-500 to-purple-600 text-white text-xs font-semibold">
{getInitials()}
@ -335,34 +302,22 @@ export function Sidebar() {
<div className="absolute -bottom-0.5 -right-0.5 w-2 h-2 bg-green-400 rounded-full border-2 border-white/40"></div>
</div>
<div className="flex-1 min-w-0">
<p
className="text-white text-xs font-medium mb-0.5 break-words"
title={getOrganizationName()}
>
<p className="text-white text-xs font-medium mb-0.5 break-words" title={getOrganizationName()}>
{getOrganizationName()}
</p>
<div className="flex items-center space-x-1">
<div className="w-1 h-1 bg-purple-400 rounded-full flex-shrink-0"></div>
<p className="text-white/50 text-[10px]">
{getCabinetType()}
</p>
<p className="text-white/50 text-[10px]">{getCabinetType()}</p>
</div>
</div>
</div>
) : (
// Свернутое состояние - только аватар
<div className="flex justify-center">
<div
className="relative"
title={`${getOrganizationName()} - ${getCabinetType()}`}
>
<div className="relative" title={`${getOrganizationName()} - ${getCabinetType()}`}>
<Avatar className="h-7 w-7 ring-2 ring-white/40">
{user?.avatar ? (
<AvatarImage
src={user.avatar}
alt="Аватар пользователя"
className="w-full h-full object-cover"
/>
<AvatarImage src={user.avatar} alt="Аватар пользователя" className="w-full h-full object-cover" />
) : null}
<AvatarFallback className="bg-gradient-to-br from-purple-500 to-purple-600 text-white text-[10px] font-semibold">
{getInitials()}
@ -378,56 +333,48 @@ export function Sidebar() {
<div className="space-y-1 mb-3 flex-1">
{/* Кнопка Главная - первая для всех типов кабинетов */}
<Button
variant={isHomeActive ? "secondary" : "ghost"}
variant={isHomeActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isHomeActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleHomeClick}
title={isCollapsed ? "Главная" : ""}
title={isCollapsed ? 'Главная' : ''}
>
<Home
className={`${
isCollapsed ? "h-4 w-4" : "h-4 w-4"
} flex-shrink-0`}
/>
<Home className={`${isCollapsed ? 'h-4 w-4' : 'h-4 w-4'} flex-shrink-0`} />
{!isCollapsed && <span className="ml-3">Главная</span>}
</Button>
<Button
variant={isMarketActive ? "secondary" : "ghost"}
variant={isMarketActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isMarketActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleMarketClick}
title={isCollapsed ? "Маркет" : ""}
title={isCollapsed ? 'Маркет' : ''}
>
<Store
className={`${
isCollapsed ? "h-4 w-4" : "h-4 w-4"
} flex-shrink-0`}
/>
<Store className={`${isCollapsed ? 'h-4 w-4' : 'h-4 w-4'} flex-shrink-0`} />
{!isCollapsed && <span className="ml-3">Маркет</span>}
</Button>
<Button
variant={isMessengerActive ? "secondary" : "ghost"}
variant={isMessengerActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs relative ${
isMessengerActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleMessengerClick}
title={isCollapsed ? "Мессенджер" : ""}
title={isCollapsed ? 'Мессенджер' : ''}
>
<MessageCircle className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Мессенджер</span>}
@ -435,31 +382,25 @@ export function Sidebar() {
{totalUnreadCount > 0 && (
<div
className={`absolute ${
isCollapsed
? "top-1 right-1 w-3 h-3"
: "top-2 right-2 w-4 h-4"
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
? ""
: totalUnreadCount > 99
? "99+"
: totalUnreadCount}
{isCollapsed ? '' : totalUnreadCount > 99 ? '99+' : totalUnreadCount}
</div>
)}
</Button>
<Button
variant={isPartnersActive ? "secondary" : "ghost"}
variant={isPartnersActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
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"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handlePartnersClick}
title={isCollapsed ? "Партнёры" : ""}
title={isCollapsed ? 'Партнёры' : ''}
>
<Handshake className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Партнёры</span>}
@ -467,33 +408,27 @@ export function Sidebar() {
{incomingRequestsCount > 0 && (
<div
className={`absolute ${
isCollapsed
? "top-1 right-1 w-3 h-3"
: "top-2 right-2 w-4 h-4"
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}
{isCollapsed ? '' : incomingRequestsCount > 99 ? '99+' : incomingRequestsCount}
</div>
)}
</Button>
{/* Услуги - только для фулфилмент центров */}
{user?.organization?.type === "FULFILLMENT" && (
{user?.organization?.type === 'FULFILLMENT' && (
<Button
variant={isServicesActive ? "secondary" : "ghost"}
variant={isServicesActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isServicesActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleServicesClick}
title={isCollapsed ? "Услуги" : ""}
title={isCollapsed ? 'Услуги' : ''}
>
<Wrench className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Услуги</span>}
@ -501,18 +436,18 @@ export function Sidebar() {
)}
{/* Сотрудники - только для фулфилмент центров */}
{user?.organization?.type === "FULFILLMENT" && (
{user?.organization?.type === 'FULFILLMENT' && (
<Button
variant={isEmployeesActive ? "secondary" : "ghost"}
variant={isEmployeesActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isEmployeesActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleEmployeesClick}
title={isCollapsed ? "Сотрудники" : ""}
title={isCollapsed ? 'Сотрудники' : ''}
>
<Users className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Сотрудники</span>}
@ -520,18 +455,18 @@ export function Sidebar() {
)}
{/* Мои поставки - для селлеров */}
{user?.organization?.type === "SELLER" && (
{user?.organization?.type === 'SELLER' && (
<Button
variant={isSuppliesActive ? "secondary" : "ghost"}
variant={isSuppliesActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isSuppliesActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer relative`}
onClick={handleSuppliesClick}
title={isCollapsed ? "Мои поставки" : ""}
title={isCollapsed ? 'Мои поставки' : ''}
>
<Truck className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Мои поставки</span>}
@ -540,18 +475,18 @@ export function Sidebar() {
)}
{/* Склад - для селлеров */}
{user?.organization?.type === "SELLER" && (
{user?.organization?.type === 'SELLER' && (
<Button
variant={isWBWarehouseActive ? "secondary" : "ghost"}
variant={isWBWarehouseActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isWBWarehouseActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleWBWarehouseClick}
title={isCollapsed ? "Склад" : ""}
title={isCollapsed ? 'Склад' : ''}
>
<Warehouse className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Склад</span>}
@ -559,18 +494,18 @@ export function Sidebar() {
)}
{/* Статистика - для селлеров */}
{user?.organization?.type === "SELLER" && (
{user?.organization?.type === 'SELLER' && (
<Button
variant={isSellerStatisticsActive ? "secondary" : "ghost"}
variant={isSellerStatisticsActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isSellerStatisticsActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleSellerStatisticsClick}
title={isCollapsed ? "Статистика" : ""}
title={isCollapsed ? 'Статистика' : ''}
>
<BarChart3 className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Статистика</span>}
@ -578,41 +513,39 @@ export function Sidebar() {
)}
{/* Входящие поставки - для фулфилмент */}
{user?.organization?.type === "FULFILLMENT" && (
{user?.organization?.type === 'FULFILLMENT' && (
<Button
variant={isSuppliesActive ? "secondary" : "ghost"}
variant={isSuppliesActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isSuppliesActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer relative`}
onClick={handleSuppliesClick}
title={isCollapsed ? "Входящие поставки" : ""}
title={isCollapsed ? 'Входящие поставки' : ''}
>
<Truck className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && (
<span className="ml-3">Входящие поставки</span>
)}
{!isCollapsed && <span className="ml-3">Входящие поставки</span>}
{/* Уведомление только о поставках, не о заявках на партнерство */}
<FulfillmentSuppliesNotification />
</Button>
)}
{/* Склад - для фулфилмент */}
{user?.organization?.type === "FULFILLMENT" && (
{user?.organization?.type === 'FULFILLMENT' && (
<Button
variant={isFulfillmentWarehouseActive ? "secondary" : "ghost"}
variant={isFulfillmentWarehouseActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isFulfillmentWarehouseActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleFulfillmentWarehouseClick}
title={isCollapsed ? "Склад" : ""}
title={isCollapsed ? 'Склад' : ''}
>
<Warehouse className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Склад</span>}
@ -620,18 +553,18 @@ export function Sidebar() {
)}
{/* Статистика - для фулфилмент */}
{user?.organization?.type === "FULFILLMENT" && (
{user?.organization?.type === 'FULFILLMENT' && (
<Button
variant={isFulfillmentStatisticsActive ? "secondary" : "ghost"}
variant={isFulfillmentStatisticsActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isFulfillmentStatisticsActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleFulfillmentStatisticsClick}
title={isCollapsed ? "Статистика" : ""}
title={isCollapsed ? 'Статистика' : ''}
>
<BarChart3 className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Статистика</span>}
@ -639,18 +572,18 @@ export function Sidebar() {
)}
{/* Заявки - для поставщиков */}
{user?.organization?.type === "WHOLESALE" && (
{user?.organization?.type === 'WHOLESALE' && (
<Button
variant={isSuppliesActive ? "secondary" : "ghost"}
variant={isSuppliesActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isSuppliesActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer relative`}
onClick={handleSuppliesClick}
title={isCollapsed ? "Заявки" : ""}
title={isCollapsed ? 'Заявки' : ''}
>
<Truck className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Заявки</span>}
@ -660,18 +593,18 @@ export function Sidebar() {
)}
{/* Перевозки - для логистов */}
{user?.organization?.type === "LOGIST" && (
{user?.organization?.type === 'LOGIST' && (
<Button
variant={isSuppliesActive ? "secondary" : "ghost"}
variant={isSuppliesActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isSuppliesActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer relative`}
onClick={handleSuppliesClick}
title={isCollapsed ? "Перевозки" : ""}
title={isCollapsed ? 'Перевозки' : ''}
>
<Truck className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Перевозки</span>}
@ -681,18 +614,18 @@ export function Sidebar() {
)}
{/* Склад - только для поставщиков */}
{user?.organization?.type === "WHOLESALE" && (
{user?.organization?.type === 'WHOLESALE' && (
<Button
variant={isWarehouseActive ? "secondary" : "ghost"}
variant={isWarehouseActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isWarehouseActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleWarehouseClick}
title={isCollapsed ? "Склад" : ""}
title={isCollapsed ? 'Склад' : ''}
>
<Warehouse className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Склад</span>}
@ -701,36 +634,32 @@ export function Sidebar() {
{/* Кнопка Экономика - для всех типов кабинетов, перед настройками */}
<Button
variant={isEconomicsActive ? "secondary" : "ghost"}
variant={isEconomicsActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isEconomicsActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleEconomicsClick}
title={isCollapsed ? "Экономика" : ""}
title={isCollapsed ? 'Экономика' : ''}
>
<DollarSign
className={`${
isCollapsed ? "h-4 w-4" : "h-4 w-4"
} flex-shrink-0`}
/>
<DollarSign className={`${isCollapsed ? 'h-4 w-4' : 'h-4 w-4'} flex-shrink-0`} />
{!isCollapsed && <span className="ml-3">Экономика</span>}
</Button>
<Button
variant={isSettingsActive ? "secondary" : "ghost"}
variant={isSettingsActive ? 'secondary' : 'ghost'}
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-left transition-all duration-200 text-xs ${
isSettingsActive
? "bg-white/20 text-white hover:bg-white/30"
: "text-white/80 hover:bg-white/10 hover:text-white"
? 'bg-white/20 text-white hover:bg-white/30'
: 'text-white/80 hover:bg-white/10 hover:text-white'
} cursor-pointer`}
onClick={handleSettingsClick}
title={isCollapsed ? "Настройки профиля" : ""}
title={isCollapsed ? 'Настройки профиля' : ''}
>
<Settings className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Настройки профиля</span>}
@ -742,10 +671,10 @@ export function Sidebar() {
<Button
variant="ghost"
className={`w-full ${
isCollapsed ? "justify-center px-2 h-9" : "justify-start h-10"
isCollapsed ? 'justify-center px-2 h-9' : 'justify-start h-10'
} text-white/80 hover:bg-red-500/20 hover:text-red-300 cursor-pointer text-xs transition-all duration-200`}
onClick={logout}
title={isCollapsed ? "Выйти" : ""}
title={isCollapsed ? 'Выйти' : ''}
>
<LogOut className="h-4 w-4 flex-shrink-0" />
{!isCollapsed && <span className="ml-3">Выйти</span>}
@ -754,5 +683,5 @@ export function Sidebar() {
</div>
</div>
</div>
);
)
}