299 lines
11 KiB
TypeScript
299 lines
11 KiB
TypeScript
"use client"
|
||
|
||
import { useState } from 'react'
|
||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||
import { Card } from '@/components/ui/card'
|
||
import { Button } from '@/components/ui/button'
|
||
import { Badge } from '@/components/ui/badge'
|
||
import { ShoppingCart, Package, Plus, Calendar, TrendingUp, AlertCircle, Building2 } from 'lucide-react'
|
||
|
||
interface MarketplaceSupply {
|
||
id: string
|
||
name: string
|
||
marketplace: 'wildberries' | 'ozon'
|
||
category: string
|
||
quantity: number
|
||
status: 'planned' | 'in-transit' | 'delivered' | 'accepted'
|
||
date: string
|
||
warehouse: string
|
||
amount: number
|
||
sku: string
|
||
}
|
||
|
||
const mockMarketplaceSupplies: MarketplaceSupply[] = [
|
||
{
|
||
id: '1',
|
||
name: 'Наушники AirPods Pro',
|
||
marketplace: 'wildberries',
|
||
category: 'Аудио',
|
||
quantity: 30,
|
||
status: 'delivered',
|
||
date: '2024-01-20',
|
||
warehouse: 'WB Подольск',
|
||
amount: 750000,
|
||
sku: 'APL-AP-PRO2'
|
||
},
|
||
{
|
||
id: '2',
|
||
name: 'Смарт часы Apple Watch',
|
||
marketplace: 'ozon',
|
||
category: 'Электроника',
|
||
quantity: 25,
|
||
status: 'in-transit',
|
||
date: '2024-01-22',
|
||
warehouse: 'Ozon Тверь',
|
||
amount: 1250000,
|
||
sku: 'APL-AW-S9'
|
||
},
|
||
{
|
||
id: '3',
|
||
name: 'Зарядные устройства',
|
||
marketplace: 'wildberries',
|
||
category: 'Аксессуары',
|
||
quantity: 100,
|
||
status: 'accepted',
|
||
date: '2024-01-18',
|
||
warehouse: 'WB Электросталь',
|
||
amount: 350000,
|
||
sku: 'ACC-CHG-20W'
|
||
}
|
||
]
|
||
|
||
export function MarketplaceSuppliesTab() {
|
||
const [activeMarketplace, setActiveMarketplace] = useState<'all' | 'wildberries' | 'ozon'>('all')
|
||
|
||
const formatCurrency = (amount: number) => {
|
||
return new Intl.NumberFormat('ru-RU', {
|
||
style: 'currency',
|
||
currency: 'RUB',
|
||
minimumFractionDigits: 0
|
||
}).format(amount)
|
||
}
|
||
|
||
const formatDate = (dateString: string) => {
|
||
return new Date(dateString).toLocaleDateString('ru-RU', {
|
||
day: '2-digit',
|
||
month: '2-digit',
|
||
year: 'numeric'
|
||
})
|
||
}
|
||
|
||
const getStatusBadge = (status: string) => {
|
||
const statusConfig = {
|
||
planned: { variant: 'outline' as const, color: 'text-blue-300 border-blue-400/30', label: 'Запланировано' },
|
||
'in-transit': { variant: 'outline' as const, color: 'text-yellow-300 border-yellow-400/30', label: 'В пути' },
|
||
delivered: { variant: 'outline' as const, color: 'text-green-300 border-green-400/30', label: 'Доставлено' },
|
||
accepted: { variant: 'outline' as const, color: 'text-purple-300 border-purple-400/30', label: 'Принято' }
|
||
}
|
||
|
||
const config = statusConfig[status as keyof typeof statusConfig] || statusConfig.planned
|
||
|
||
return (
|
||
<Badge variant={config.variant} className={`glass-secondary ${config.color}`}>
|
||
{config.label}
|
||
</Badge>
|
||
)
|
||
}
|
||
|
||
const getMarketplaceBadge = (marketplace: string) => {
|
||
if (marketplace === 'wildberries') {
|
||
return (
|
||
<Badge variant="outline" className="glass-secondary text-purple-300 border-purple-400/30">
|
||
Wildberries
|
||
</Badge>
|
||
)
|
||
} else if (marketplace === 'ozon') {
|
||
return (
|
||
<Badge variant="outline" className="glass-secondary text-blue-300 border-blue-400/30">
|
||
Ozon
|
||
</Badge>
|
||
)
|
||
}
|
||
return null
|
||
}
|
||
|
||
const filteredSupplies = activeMarketplace === 'all'
|
||
? mockMarketplaceSupplies
|
||
: mockMarketplaceSupplies.filter(supply => supply.marketplace === activeMarketplace)
|
||
|
||
const getTotalAmount = () => {
|
||
return filteredSupplies.reduce((sum, supply) => sum + supply.amount, 0)
|
||
}
|
||
|
||
const getTotalQuantity = () => {
|
||
return filteredSupplies.reduce((sum, supply) => sum + supply.quantity, 0)
|
||
}
|
||
|
||
return (
|
||
<div className="h-full flex flex-col space-y-4 p-4">
|
||
{/* Компактный заголовок */}
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-2">
|
||
<ShoppingCart className="h-4 w-4 text-purple-400" />
|
||
<span className="text-white font-medium text-sm">Маркетплейсы</span>
|
||
</div>
|
||
<Button
|
||
size="sm"
|
||
className="bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white text-xs"
|
||
>
|
||
<Plus className="h-3 w-3 mr-1" />
|
||
Создать
|
||
</Button>
|
||
</div>
|
||
|
||
{/* Компактная статистика */}
|
||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3">
|
||
<Card className="glass-card p-3">
|
||
<div className="flex items-center space-x-2">
|
||
<div className="p-1.5 bg-purple-500/20 rounded">
|
||
<Package className="h-3 w-3 text-purple-400" />
|
||
</div>
|
||
<div>
|
||
<p className="text-white/60 text-xs">Поставок</p>
|
||
<p className="text-lg font-bold text-white">{filteredSupplies.length}</p>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
|
||
<Card className="glass-card p-4">
|
||
<div className="flex items-center space-x-3">
|
||
<div className="p-2 bg-green-500/20 rounded-lg">
|
||
<TrendingUp className="h-5 w-5 text-green-400" />
|
||
</div>
|
||
<div>
|
||
<p className="text-white/60 text-sm">Общая сумма</p>
|
||
<p className="text-xl font-bold text-white">{formatCurrency(getTotalAmount())}</p>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
|
||
<Card className="glass-card p-4">
|
||
<div className="flex items-center space-x-3">
|
||
<div className="p-2 bg-blue-500/20 rounded-lg">
|
||
<AlertCircle className="h-5 w-5 text-blue-400" />
|
||
</div>
|
||
<div>
|
||
<p className="text-white/60 text-sm">Единиц товара</p>
|
||
<p className="text-xl font-bold text-white">{getTotalQuantity()}</p>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
|
||
<Card className="glass-card p-4">
|
||
<div className="flex items-center space-x-3">
|
||
<div className="p-2 bg-yellow-500/20 rounded-lg">
|
||
<Calendar className="h-5 w-5 text-yellow-400" />
|
||
</div>
|
||
<div>
|
||
<p className="text-white/60 text-sm">В пути</p>
|
||
<p className="text-xl font-bold text-white">
|
||
{filteredSupplies.filter(s => s.status === 'in-transit').length}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
</div>
|
||
|
||
{/* Фильтры по маркетплейсу */}
|
||
<div className="flex items-center space-x-2">
|
||
<span className="text-white/60 text-sm">Маркетплейс:</span>
|
||
<div className="flex space-x-2">
|
||
<Button
|
||
variant={activeMarketplace === 'all' ? 'secondary' : 'ghost'}
|
||
size="sm"
|
||
onClick={() => setActiveMarketplace('all')}
|
||
className={`${activeMarketplace === 'all' ? 'bg-white/20 text-white' : 'text-white/70 hover:bg-white/10'}`}
|
||
>
|
||
Все
|
||
</Button>
|
||
<Button
|
||
variant={activeMarketplace === 'wildberries' ? 'secondary' : 'ghost'}
|
||
size="sm"
|
||
onClick={() => setActiveMarketplace('wildberries')}
|
||
className={`${activeMarketplace === 'wildberries' ? 'bg-white/20 text-white' : 'text-white/70 hover:bg-white/10'} flex items-center gap-1`}
|
||
>
|
||
<div className="w-3 h-3 bg-purple-400 rounded-full"></div>
|
||
Wildberries
|
||
</Button>
|
||
<Button
|
||
variant={activeMarketplace === 'ozon' ? 'secondary' : 'ghost'}
|
||
size="sm"
|
||
onClick={() => setActiveMarketplace('ozon')}
|
||
className={`${activeMarketplace === 'ozon' ? 'bg-white/20 text-white' : 'text-white/70 hover:bg-white/10'} flex items-center gap-1`}
|
||
>
|
||
<div className="w-3 h-3 bg-blue-400 rounded-full"></div>
|
||
Ozon
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Таблица поставок */}
|
||
<Card className="glass-card flex-1 overflow-hidden">
|
||
<div className="p-6 h-full flex flex-col">
|
||
<div className="overflow-x-auto flex-1">
|
||
<table className="w-full">
|
||
<thead>
|
||
<tr className="border-b border-white/20">
|
||
<th className="text-left p-3 text-white font-semibold">Маркетплейс</th>
|
||
<th className="text-left p-3 text-white font-semibold">Наименование</th>
|
||
<th className="text-left p-3 text-white font-semibold">SKU</th>
|
||
<th className="text-left p-3 text-white font-semibold">Категория</th>
|
||
<th className="text-left p-3 text-white font-semibold">Количество</th>
|
||
<th className="text-left p-3 text-white font-semibold">Склад</th>
|
||
<th className="text-left p-3 text-white font-semibold">Дата</th>
|
||
<th className="text-left p-3 text-white font-semibold">Сумма</th>
|
||
<th className="text-left p-3 text-white font-semibold">Статус</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{filteredSupplies.map((supply) => (
|
||
<tr key={supply.id} className="border-b border-white/10 hover:bg-white/5 transition-colors">
|
||
<td className="p-3">
|
||
{getMarketplaceBadge(supply.marketplace)}
|
||
</td>
|
||
<td className="p-3">
|
||
<span className="text-white font-medium">{supply.name}</span>
|
||
</td>
|
||
<td className="p-3">
|
||
<span className="text-white/80 font-mono text-sm">{supply.sku}</span>
|
||
</td>
|
||
<td className="p-3">
|
||
<span className="text-white/80">{supply.category}</span>
|
||
</td>
|
||
<td className="p-3">
|
||
<span className="text-white font-semibold">{supply.quantity}</span>
|
||
</td>
|
||
<td className="p-3">
|
||
<span className="text-white/80">{supply.warehouse}</span>
|
||
</td>
|
||
<td className="p-3">
|
||
<span className="text-white/80">{formatDate(supply.date)}</span>
|
||
</td>
|
||
<td className="p-3">
|
||
<span className="text-white font-semibold">{formatCurrency(supply.amount)}</span>
|
||
</td>
|
||
<td className="p-3">
|
||
{getStatusBadge(supply.status)}
|
||
</td>
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
|
||
{filteredSupplies.length === 0 && (
|
||
<div className="flex items-center justify-center p-8">
|
||
<div className="text-center">
|
||
<ShoppingCart className="h-12 w-12 text-white/20 mx-auto mb-4" />
|
||
<p className="text-white/60">Поставки не найдены</p>
|
||
<p className="text-white/40 text-sm mt-2">
|
||
Измените фильтр или создайте новую поставку
|
||
</p>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</Card>
|
||
</div>
|
||
)
|
||
}
|