Изменен механизм выбора вкладок в компоненте CreateSupplyPage: заменено состояние selectedVariant на activeTab для улучшения читаемости кода. Обновлены условия отображения корзины и логика обработки товаров. Оптимизирован рендеринг карточек и оптовиков. В компоненте WBProductCards изменен заголовок на "Нет товаров" при отсутствии выбранных карточек.

This commit is contained in:
Bivekich
2025-07-23 14:19:59 +03:00
parent ac3578aa7f
commit ff873482a5
2 changed files with 350 additions and 432 deletions

View File

@ -255,7 +255,7 @@ const mockProducts: WholesalerProduct[] = [
export function CreateSupplyPage() {
const router = useRouter()
const { getSidebarMargin } = useSidebar()
const [selectedVariant, setSelectedVariant] = useState<'cards' | 'wholesaler' | null>(null)
const [activeTab, setActiveTab] = useState<'cards' | 'wholesaler'>('cards')
const [selectedWholesaler, setSelectedWholesaler] = useState<WholesalerForCreation | null>(null)
const [selectedProducts, setSelectedProducts] = useState<SelectedProduct[]>([])
const [selectedCards, setSelectedCards] = useState<SelectedCard[]>([])
@ -290,10 +290,10 @@ export function CreateSupplyPage() {
// Автоматически показываем корзину если в ней есть товары и мы на этапе выбора оптовиков
useEffect(() => {
if (selectedVariant === 'wholesaler' && !selectedWholesaler && selectedProducts.length > 0) {
if (activeTab === 'wholesaler' && !selectedWholesaler && selectedProducts.length > 0) {
setShowSummary(true)
}
}, [selectedVariant, selectedWholesaler, selectedProducts.length])
}, [activeTab, selectedWholesaler, selectedProducts.length])
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat('ru-RU', {
@ -367,7 +367,7 @@ export function CreateSupplyPage() {
}
const handleCreateSupply = () => {
if (selectedVariant === 'cards') {
if (activeTab === 'cards') {
console.log('Создание поставки с карточками Wildberries')
// TODO: Здесь будет создание поставки с данными карточек
} else {
@ -382,17 +382,13 @@ export function CreateSupplyPage() {
setSelectedWholesaler(null)
// НЕ очищаем корзину! setSelectedProducts([])
setShowSummary(false)
} else if (selectedVariant) {
setSelectedVariant(null)
setSelectedProducts([]) // Очищаем корзину только при полном выходе
setShowSummary(false)
} else {
router.push('/supplies')
}
}
// Рендер товаров оптовика
if (selectedWholesaler && selectedVariant === 'wholesaler') {
if (selectedWholesaler && activeTab === 'wholesaler') {
return (
<div className="h-screen flex overflow-hidden">
<Sidebar />
@ -743,69 +739,93 @@ export function CreateSupplyPage() {
)
}
// Рендер карточек Wildberries
if (selectedVariant === 'cards') {
return (
<WBProductCards
onBack={() => setSelectedVariant(null)}
onComplete={handleCardsComplete}
/>
)
}
// Рендер выбора оптовиков
if (selectedVariant === 'wholesaler') {
// Главная страница с табами
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="p-8">
<div className="flex items-center justify-between mb-8">
<main className={`flex-1 ${getSidebarMargin()} px-4 py-3 overflow-hidden transition-all duration-300`}>
<div className="p-4">
{/* Верхняя строка: Назад + Заголовок + Табы */}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center space-x-4">
<Button
variant="ghost"
size="sm"
onClick={handleGoBack}
onClick={() => router.push('/supplies')}
className="text-white/60 hover:text-white hover:bg-white/10"
>
<ArrowLeft className="h-4 w-4 mr-2" />
Назад
</Button>
<h1 className="text-2xl font-bold text-white">Создание поставки</h1>
</div>
<div>
<h1 className="text-3xl font-bold text-white mb-2">Выбор оптовика</h1>
<p className="text-white/60">
{selectedProducts.length > 0
? `Выберите еще оптовика или перейдите к оформлению (${selectedProducts.length} товаров в корзине)`
: "Выберите оптовика для создания поставки"
}
</p>
</div>
</div>
{selectedProducts.length > 0 && (
<Button
variant="ghost"
size="sm"
onClick={() => setShowSummary(!showSummary)}
className="text-white/60 hover:text-white hover:bg-white/10"
<div className="grid grid-cols-2 bg-white/10 backdrop-blur border border-white/20 rounded-lg p-1">
<button
onClick={() => setActiveTab('cards')}
className={`px-4 py-2 text-sm rounded transition-all ${
activeTab === 'cards'
? 'bg-white/20 text-white'
: 'text-white/60 hover:text-white hover:bg-white/10'
}`}
>
<ShoppingCart className="h-4 w-4 mr-2" />
Корзина ({selectedProducts.length})
</Button>
<ShoppingCart className="h-4 w-4 mr-1 inline" />
Карточки
</button>
<button
onClick={() => setActiveTab('wholesaler')}
className={`px-4 py-2 text-sm rounded transition-all ${
activeTab === 'wholesaler'
? 'bg-white/20 text-white'
: 'text-white/60 hover:text-white hover:bg-white/10'
}`}
>
<Users className="h-4 w-4 mr-1 inline" />
Оптовики
</button>
</div>
</div>
</div>
{/* Контент карточек */}
{activeTab === 'cards' && (
<WBProductCards
onBack={() => router.push('/supplies')}
onComplete={handleCardsComplete}
/>
)}
{/* Контент оптовиков */}
{activeTab === 'wholesaler' && (
<div>
{/* Поиск */}
<div className="mb-4">
<div className="relative max-w-md">
<Search className="absolute left-3 top-3 h-4 w-4 text-white/40" />
<Input
placeholder="Поиск оптовиков..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-10 glass-input text-white placeholder:text-white/40 h-10"
/>
</div>
</div>
{/* Корзина */}
{showSummary && selectedProducts.length > 0 && (
<Card className="bg-gradient-to-br from-purple-500/10 to-pink-500/10 backdrop-blur-xl border border-purple-500/20 mb-8 shadow-2xl">
<div className="p-6">
<div className="flex items-center justify-between mb-6">
<Card className="bg-gradient-to-br from-purple-500/10 to-pink-500/10 backdrop-blur-xl border border-purple-500/20 mb-6 shadow-2xl">
<div className="p-4">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center space-x-3">
<div className="p-3 bg-gradient-to-r from-purple-500 to-pink-500 rounded-xl">
<ShoppingCart className="h-6 w-6 text-white" />
<div className="p-2 bg-gradient-to-r from-purple-500 to-pink-500 rounded-lg">
<ShoppingCart className="h-5 w-5 text-white" />
</div>
<div>
<h3 className="text-white font-bold text-xl">Корзина</h3>
<p className="text-purple-200 text-sm">{selectedProducts.length} товаров от {Object.keys(selectedProducts.reduce((acc, p) => ({ ...acc, [p.wholesalerId]: true }), {})).length} поставщиков</p>
<h3 className="text-white font-bold text-lg">Корзина</h3>
<p className="text-purple-200 text-xs">{selectedProducts.length} товаров от {Object.keys(selectedProducts.reduce((acc, p) => ({ ...acc, [p.wholesalerId]: true }), {})).length} поставщиков</p>
</div>
</div>
<Button
@ -831,8 +851,8 @@ export function CreateSupplyPage() {
return acc
}, {} as Record<string, { wholesaler: string; products: SelectedProduct[] }>)
).map(([wholesalerId, group]) => (
<div key={wholesalerId} className="mb-6 last:mb-0">
<div className="flex items-center mb-3 pb-2 border-b border-white/10">
<div key={wholesalerId} className="mb-4 last:mb-0">
<div className="flex items-center mb-2 pb-1 border-b border-white/10">
<Building2 className="h-4 w-4 text-blue-400 mr-2" />
<span className="text-white font-medium">{group.wholesaler}</span>
<Badge className="ml-2 bg-blue-500/20 text-blue-300 border-blue-500/30 text-xs">
@ -840,7 +860,7 @@ export function CreateSupplyPage() {
</Badge>
</div>
<div className="space-y-3">
<div className="space-y-2">
{group.products.map((product) => {
const discountedPrice = product.discount
? product.price * (1 - product.discount / 100)
@ -848,16 +868,16 @@ export function CreateSupplyPage() {
const totalPrice = discountedPrice * product.selectedQuantity
return (
<div key={`${product.wholesalerId}-${product.id}`} className="flex items-center space-x-4 bg-white/5 rounded-lg p-4">
<div key={`${product.wholesalerId}-${product.id}`} className="flex items-center space-x-3 bg-white/5 rounded-lg p-3">
<img
src={product.mainImage || '/api/placeholder/60/60'}
src={product.mainImage || '/api/placeholder/50/50'}
alt={product.name}
className="w-16 h-16 rounded-lg object-cover"
className="w-12 h-12 rounded-lg object-cover"
/>
<div className="flex-1 min-w-0">
<h4 className="text-white font-medium text-sm mb-1 truncate">{product.name}</h4>
<p className="text-white/60 text-xs mb-2">{product.article}</p>
<div className="flex items-center space-x-3">
<h4 className="text-white font-medium text-xs mb-1 truncate">{product.name}</h4>
<p className="text-white/60 text-xs mb-1">{product.article}</p>
<div className="flex items-center space-x-2">
<div className="flex items-center space-x-1">
<Button
variant="ghost"
@ -878,11 +898,11 @@ export function CreateSupplyPage() {
)
}
}}
className="h-7 w-7 p-0 text-white/60 hover:text-white hover:bg-white/10"
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
>
<Minus className="h-3 w-3" />
</Button>
<span className="text-white text-sm w-8 text-center">{product.selectedQuantity}</span>
<span className="text-white text-xs w-6 text-center">{product.selectedQuantity}</span>
<Button
variant="ghost"
size="sm"
@ -896,13 +916,13 @@ export function CreateSupplyPage() {
)
}}
disabled={product.selectedQuantity >= product.quantity}
className="h-7 w-7 p-0 text-white/60 hover:text-white hover:bg-white/10"
className="h-6 w-6 p-0 text-white/60 hover:text-white hover:bg-white/10"
>
<Plus className="h-3 w-3" />
</Button>
</div>
<div className="text-right">
<div className="text-white font-semibold text-sm">{formatCurrency(totalPrice)}</div>
<div className="text-white font-semibold text-xs">{formatCurrency(totalPrice)}</div>
{product.discount && (
<div className="text-white/40 text-xs line-through">
{formatCurrency(product.price * product.selectedQuantity)}
@ -931,16 +951,16 @@ export function CreateSupplyPage() {
))}
{/* Итого */}
<div className="border-t border-white/20 pt-4 mt-6">
<div className="border-t border-white/20 pt-3 mt-4">
<div className="flex justify-between items-center">
<span className="text-white font-semibold text-lg">
<span className="text-white font-semibold text-sm">
Итого: {getTotalItems()} товаров
</span>
<span className="text-white font-bold text-2xl">
<span className="text-white font-bold text-lg">
{formatCurrency(getTotalAmount())}
</span>
</div>
<div className="flex space-x-3 mt-4">
<div className="flex space-x-2 mt-3">
<Button
variant="outline"
className="flex-1 border-purple-300/30 text-white hover:bg-white/10"
@ -962,19 +982,6 @@ export function CreateSupplyPage() {
</Card>
)}
{/* Поиск */}
<div className="mb-6">
<div className="relative">
<Search className="absolute left-3 top-3 h-4 w-4 text-white/40" />
<Input
placeholder="Поиск оптовиков по названию или ИНН..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-10 glass-input text-white placeholder:text-white/40"
/>
</div>
</div>
{counterpartiesLoading ? (
<div className="flex items-center justify-center p-8">
<div className="text-center">
@ -993,7 +1000,7 @@ export function CreateSupplyPage() {
</p>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{filteredWholesalers.map((wholesaler: {
id: string;
name?: string;
@ -1005,7 +1012,7 @@ export function CreateSupplyPage() {
}) => (
<Card
key={wholesaler.id}
className="bg-white/10 backdrop-blur border-white/20 p-6 cursor-pointer transition-all hover:bg-white/15 hover:border-white/30 hover:scale-105"
className="bg-white/10 backdrop-blur border-white/20 p-4 cursor-pointer transition-all hover:bg-white/15 hover:border-white/30 hover:scale-[1.02]"
onClick={() => {
// Адаптируем данные под существующий интерфейс
const adaptedWholesaler = {
@ -1023,16 +1030,16 @@ export function CreateSupplyPage() {
setSelectedWholesaler(adaptedWholesaler)
}}
>
<div className="space-y-4">
<div className="flex items-start space-x-3">
<div className="p-3 bg-blue-500/20 rounded-lg">
<Building2 className="h-6 w-6 text-blue-400" />
<div className="space-y-3">
<div className="flex items-start space-x-2">
<div className="p-2 bg-blue-500/20 rounded-lg">
<Building2 className="h-4 w-4 text-blue-400" />
</div>
<div className="flex-1 min-w-0">
<h3 className="text-white font-semibold text-lg mb-1 truncate">
<h3 className="text-white font-semibold text-sm mb-1 truncate">
{wholesaler.name || 'Неизвестная организация'}
</h3>
<p className="text-white/60 text-xs mb-2 truncate">
<p className="text-white/60 text-xs mb-1 truncate">
{wholesaler.fullName || wholesaler.name}
</p>
{wholesaler.inn && (
@ -1043,31 +1050,31 @@ export function CreateSupplyPage() {
</div>
</div>
<div className="space-y-2">
<div className="space-y-1">
{wholesaler.address && (
<div className="flex items-center space-x-2">
<MapPin className="h-4 w-4 text-gray-400" />
<span className="text-white/80 text-sm truncate">{wholesaler.address}</span>
<div className="flex items-center space-x-1">
<MapPin className="h-3 w-3 text-gray-400" />
<span className="text-white/80 text-xs truncate">{wholesaler.address}</span>
</div>
)}
{wholesaler.phones?.[0]?.value && (
<div className="flex items-center space-x-2">
<Phone className="h-4 w-4 text-gray-400" />
<span className="text-white/80 text-sm">{wholesaler.phones[0].value}</span>
<div className="flex items-center space-x-1">
<Phone className="h-3 w-3 text-gray-400" />
<span className="text-white/80 text-xs">{wholesaler.phones[0].value}</span>
</div>
)}
{wholesaler.emails?.[0]?.value && (
<div className="flex items-center space-x-2">
<Mail className="h-4 w-4 text-gray-400" />
<span className="text-white/80 text-sm truncate">{wholesaler.emails[0].value}</span>
<div className="flex items-center space-x-1">
<Mail className="h-3 w-3 text-gray-400" />
<span className="text-white/80 text-xs truncate">{wholesaler.emails[0].value}</span>
</div>
)}
</div>
<div className="mt-4">
<Badge className="bg-green-500/20 text-green-300 border-green-500/30">
<div className="mt-2">
<Badge className="bg-green-500/20 text-green-300 border-green-500/30 text-xs px-2 py-1">
Контрагент
</Badge>
</div>
@ -1095,76 +1102,7 @@ export function CreateSupplyPage() {
</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="p-8">
<div className="flex items-center justify-between mb-8">
<div className="flex items-center space-x-4">
<Button
variant="ghost"
size="sm"
onClick={() => router.push('/supplies')}
className="text-white/60 hover:text-white hover:bg-white/10"
>
<ArrowLeft className="h-4 w-4 mr-2" />
Назад к поставкам
</Button>
<div>
<h1 className="text-3xl font-bold text-white mb-2">Создание поставки</h1>
<p className="text-white/60">Выберите способ создания поставки</p>
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<Card
className="bg-white/10 backdrop-blur border-white/20 p-8 cursor-pointer transition-all hover:bg-white/15 hover:border-white/30 hover:scale-105"
onClick={() => setSelectedVariant('cards')}
>
<div className="text-center space-y-6">
<div className="p-6 bg-blue-500/20 rounded-2xl w-fit mx-auto">
<ShoppingCart className="h-12 w-12 text-blue-400" />
</div>
<div>
<h3 className="text-2xl font-semibold text-white mb-3">Карточки</h3>
<p className="text-white/60">
Создание поставки через выбор товаров по карточкам Wildberries
</p>
</div>
<Badge className="bg-green-500/20 text-green-300 border-green-500/30 text-lg px-4 py-2">
Доступно
</Badge>
</div>
</Card>
<Card
className="bg-white/10 backdrop-blur border-white/20 p-8 cursor-pointer transition-all hover:bg-white/15 hover:border-white/30 hover:scale-105"
onClick={() => setSelectedVariant('wholesaler')}
>
<div className="text-center space-y-6">
<div className="p-6 bg-green-500/20 rounded-2xl w-fit mx-auto">
<Users className="h-12 w-12 text-green-400" />
</div>
<div>
<h3 className="text-2xl font-semibold text-white mb-3">Оптовик</h3>
<p className="text-white/60">
Создание поставки через выбор товаров у оптовиков
</p>
</div>
<Badge className="bg-green-500/20 text-green-300 border-green-500/30 text-lg px-4 py-2">
Доступно
</Badge>
</div>
</Card>
</div>
)}
</div>
</main>
</div>

View File

@ -997,26 +997,8 @@ export function WBProductCards({ onBack, onComplete }: WBProductCardsProps) {
}
return (
<div className="h-screen flex overflow-hidden">
<Sidebar />
<main className={`flex-1 ${getSidebarMargin()} overflow-auto transition-all duration-300`}>
<div className="p-6 space-y-6">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<Button
variant="ghost"
size="sm"
onClick={onBack}
className="text-white/60 hover:text-white hover:bg-white/10"
>
<ArrowLeft className="h-4 w-4 mr-2" />
Назад
</Button>
<div>
<h2 className="text-2xl font-bold text-white mb-1">Карточки товаров Wildberries</h2>
<p className="text-white/60">Найдите и выберите товары для поставки</p>
</div>
</div>
<div className="space-y-4">
<div className="flex items-center justify-end">
{selectedCards.length > 0 && (
<Button
@ -1324,7 +1306,7 @@ export function WBProductCards({ onBack, onComplete }: WBProductCardsProps) {
<Card className="bg-white/10 backdrop-blur border-white/20 p-8">
<div className="text-center max-w-md mx-auto">
<Package className="h-12 w-12 text-white/20 mx-auto mb-4" />
<h3 className="text-lg font-semibold text-white mb-2">Карточки товаров Wildberries</h3>
<h3 className="text-lg font-semibold text-white mb-2">Нет товаров</h3>
{user?.organization?.apiKeys?.find(key => key.marketplace === 'WILDBERRIES')?.isActive ? (
<>
<p className="text-white/60 mb-4 text-sm">
@ -1447,7 +1429,5 @@ export function WBProductCards({ onBack, onComplete }: WBProductCardsProps) {
</DialogContent>
</Dialog>
</div>
</main>
</div>
)
}