Files
sfera-new/src/components/supplies/supplier-products.tsx

469 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, { useState } from "react";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import {
ArrowLeft,
Package,
Plus,
Minus,
ShoppingCart,
Eye,
Info,
} from "lucide-react";
import Image from "next/image";
interface Supplier {
id: string;
inn: string;
name: string;
fullName: string;
address: string;
phone?: string;
email?: string;
rating: number;
productCount: number;
avatar?: string;
specialization: string[];
}
interface Product {
id: string;
name: string;
article: string;
description: string;
price: number;
quantity: number;
category: string;
brand?: string;
color?: string;
size?: string;
weight?: number;
dimensions?: string;
material?: string;
images: string[];
mainImage?: string;
}
interface SelectedProduct extends Product {
selectedQuantity: number;
}
interface SupplierProductsProps {
supplier: Supplier;
onBack: () => void;
onClose: () => void;
onSupplyCreated: () => void;
}
// Моковые данные товаров
const mockProducts: Product[] = [
{
id: "1",
name: "Смартфон Samsung Galaxy A54",
article: "SGX-A54-128",
description: 'Смартфон с экраном 6.4", камерой 50 МП, 128 ГБ памяти',
price: 28900,
quantity: 150,
category: "Смартфоны",
brand: "Samsung",
color: "Черный",
size: '6.4"',
weight: 202,
dimensions: "158.2 x 76.7 x 8.2 мм",
material: "Алюминий, стекло",
images: ["/api/placeholder/300/300?text=Samsung+A54"],
mainImage: "/api/placeholder/300/300?text=Samsung+A54",
},
{
id: "2",
name: "Наушники Sony WH-1000XM4",
article: "SNY-WH1000XM4",
description: "Беспроводные наушники с шумоподавлением",
price: 24900,
quantity: 85,
category: "Наушники",
brand: "Sony",
color: "Черный",
weight: 254,
material: "Пластик, кожа",
images: ["/api/placeholder/300/300?text=Sony+WH1000XM4"],
mainImage: "/api/placeholder/300/300?text=Sony+WH1000XM4",
},
{
id: "3",
name: 'Планшет iPad Air 10.9"',
article: "APL-IPADAIR-64",
description: "Планшет Apple iPad Air с чипом M1, 64 ГБ",
price: 54900,
quantity: 45,
category: "Планшеты",
brand: "Apple",
color: "Серый космос",
size: '10.9"',
weight: 461,
dimensions: "247.6 x 178.5 x 6.1 мм",
material: "Алюминий",
images: ["/api/placeholder/300/300?text=iPad+Air"],
mainImage: "/api/placeholder/300/300?text=iPad+Air",
},
{
id: "4",
name: "Ноутбук Lenovo ThinkPad E15",
article: "LNV-TE15-I5",
description: 'Ноутбук 15.6" Intel Core i5, 8 ГБ ОЗУ, 256 ГБ SSD',
price: 45900,
quantity: 25,
category: "Ноутбуки",
brand: "Lenovo",
color: "Черный",
size: '15.6"',
weight: 1700,
dimensions: "365 x 240 x 19.9 мм",
material: "Пластик",
images: ["/api/placeholder/300/300?text=ThinkPad+E15"],
mainImage: "/api/placeholder/300/300?text=ThinkPad+E15",
},
{
id: "5",
name: "Умные часы Apple Watch SE",
article: "APL-AWSE-40",
description: "Умные часы Apple Watch SE 40 мм",
price: 21900,
quantity: 120,
category: "Умные часы",
brand: "Apple",
color: "Белый",
size: "40 мм",
weight: 30,
dimensions: "40 x 34 x 10.7 мм",
material: "Алюминий",
images: ["/api/placeholder/300/300?text=Apple+Watch+SE"],
mainImage: "/api/placeholder/300/300?text=Apple+Watch+SE",
},
{
id: "6",
name: "Клавиатура Logitech MX Keys",
article: "LGT-MXKEYS",
description: "Беспроводная клавиатура для продуктивной работы",
price: 8900,
quantity: 75,
category: "Клавиатуры",
brand: "Logitech",
color: "Графит",
weight: 810,
dimensions: "430.2 x 20.5 x 131.6 мм",
material: "Пластик, металл",
images: ["/api/placeholder/300/300?text=MX+Keys"],
mainImage: "/api/placeholder/300/300?text=MX+Keys",
},
];
export function SupplierProducts({
supplier,
onBack,
onClose,
onSupplyCreated,
}: SupplierProductsProps) {
const [selectedProducts, setSelectedProducts] = useState<SelectedProduct[]>(
[]
);
const [showSummary, setShowSummary] = useState(false);
const formatCurrency = (amount: number) => {
return new Intl.NumberFormat("ru-RU", {
style: "currency",
currency: "RUB",
minimumFractionDigits: 0,
}).format(amount);
};
const updateProductQuantity = (productId: string, quantity: number) => {
const product = mockProducts.find((p) => p.id === productId);
if (!product) return;
setSelectedProducts((prev) => {
const existing = prev.find((p) => p.id === productId);
if (quantity === 0) {
// Удаляем продукт если количество 0
return prev.filter((p) => p.id !== productId);
}
if (existing) {
// Обновляем количество существующего продукта
return prev.map((p) =>
p.id === productId ? { ...p, selectedQuantity: quantity } : p
);
} else {
// Добавляем новый продукт
return [...prev, { ...product, selectedQuantity: quantity }];
}
});
};
const getSelectedQuantity = (productId: string): number => {
const selected = selectedProducts.find((p) => p.id === productId);
return selected ? selected.selectedQuantity : 0;
};
const getTotalAmount = () => {
return selectedProducts.reduce(
(sum, product) => sum + product.price * product.selectedQuantity,
0
);
};
const getTotalItems = () => {
return selectedProducts.reduce(
(sum, product) => sum + product.selectedQuantity,
0
);
};
const handleCreateSupply = () => {
console.log("Создание поставки с товарами:", selectedProducts);
// TODO: Здесь будет реальное создание поставки
onSupplyCreated();
};
return (
<div className="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">
Товары поставщика
</h2>
<p className="text-white/60">
{supplier.name} {mockProducts.length} товаров
</p>
</div>
</div>
<div className="flex items-center space-x-3">
<Button
variant="ghost"
size="sm"
onClick={() => setShowSummary(!showSummary)}
className="text-white/60 hover:text-white hover:bg-white/10"
>
<Info className="h-4 w-4 mr-2" />
Резюме ({selectedProducts.length})
</Button>
<Button
variant="ghost"
size="sm"
onClick={onClose}
className="text-white/60 hover:text-white hover:bg-white/10"
>
Отмена
</Button>
</div>
</div>
{showSummary && selectedProducts.length > 0 && (
<Card className="bg-purple-500/10 backdrop-blur border-purple-500/30 p-6">
<h3 className="text-white font-semibold text-lg mb-4">
Резюме заказа
</h3>
<div className="space-y-3">
{selectedProducts.map((product) => (
<div
key={product.id}
className="flex justify-between items-center"
>
<div>
<span className="text-white">{product.name}</span>
<span className="text-white/60 text-sm ml-2">
× {product.selectedQuantity}
</span>
</div>
<span className="text-white font-medium">
{formatCurrency(product.price * product.selectedQuantity)}
</span>
</div>
))}
<div className="border-t border-white/20 pt-3 flex justify-between items-center">
<span className="text-white font-semibold">
Итого: {getTotalItems()} товаров
</span>
<span className="text-white font-bold text-xl">
{formatCurrency(getTotalAmount())}
</span>
</div>
<Button
className="w-full bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600 hover:to-emerald-600 text-white"
onClick={handleCreateSupply}
disabled={selectedProducts.length === 0}
>
<ShoppingCart className="h-4 w-4 mr-2" />
Создать поставку
</Button>
</div>
</Card>
)}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{mockProducts.map((product) => {
const selectedQuantity = getSelectedQuantity(product.id);
return (
<Card
key={product.id}
className="bg-white/10 backdrop-blur border-white/20 overflow-hidden"
>
<div className="aspect-square relative bg-white/5">
<Image
src={product.mainImage || "/api/placeholder/300/300"}
alt={product.name}
fill
className="object-cover"
/>
<div className="absolute top-2 right-2">
<Badge className="bg-green-500/20 text-green-300 border-green-500/30">
В наличии: {product.quantity}
</Badge>
</div>
</div>
<div className="p-4 space-y-3">
<div>
<h3 className="text-white font-semibold mb-1 line-clamp-2">
{product.name}
</h3>
<p className="text-white/60 text-xs mb-2">
Артикул: {product.article}
</p>
<div className="flex items-center space-x-2 mb-2">
<Badge className="bg-blue-500/20 text-blue-300 border-blue-500/30 text-xs">
{product.category}
</Badge>
{product.brand && (
<Badge className="bg-gray-500/20 text-gray-300 border-gray-500/30 text-xs">
{product.brand}
</Badge>
)}
</div>
</div>
<p className="text-white/60 text-sm line-clamp-2">
{product.description}
</p>
<div className="space-y-2">
{product.color && (
<div className="text-white/60 text-xs">
Цвет: <span className="text-white">{product.color}</span>
</div>
)}
{product.size && (
<div className="text-white/60 text-xs">
Размер: <span className="text-white">{product.size}</span>
</div>
)}
{product.weight && (
<div className="text-white/60 text-xs">
Вес:{" "}
<span className="text-white">{product.weight} г</span>
</div>
)}
</div>
<div className="flex items-center justify-between pt-2 border-t border-white/10">
<div>
<div className="text-white font-bold text-lg">
{formatCurrency(product.price)}
</div>
<div className="text-white/60 text-xs">за штуку</div>
</div>
</div>
<div className="flex items-center space-x-2">
<Button
variant="ghost"
size="sm"
onClick={() =>
updateProductQuantity(
product.id,
Math.max(0, selectedQuantity - 1)
)
}
disabled={selectedQuantity === 0}
className="h-8 w-8 p-0 text-white/60 hover:text-white hover:bg-white/10"
>
<Minus className="h-4 w-4" />
</Button>
<Input
type="number"
value={selectedQuantity}
onChange={(e) => {
const value = Math.max(
0,
Math.min(
product.quantity,
parseInt(e.target.value) || 0
)
);
updateProductQuantity(product.id, value);
}}
className="h-8 w-16 text-center bg-white/10 border-white/20 text-white"
min={0}
max={product.quantity}
/>
<Button
variant="ghost"
size="sm"
onClick={() =>
updateProductQuantity(
product.id,
Math.min(product.quantity, selectedQuantity + 1)
)
}
disabled={selectedQuantity >= product.quantity}
className="h-8 w-8 p-0 text-white/60 hover:text-white hover:bg-white/10"
>
<Plus className="h-4 w-4" />
</Button>
</div>
{selectedQuantity > 0 && (
<div className="bg-green-500/20 border border-green-500/30 rounded-lg p-2">
<div className="text-green-300 text-sm font-medium">
Сумма: {formatCurrency(product.price * selectedQuantity)}
</div>
</div>
)}
</div>
</Card>
);
})}
</div>
{selectedProducts.length > 0 && (
<div className="fixed bottom-6 right-6">
<Button
className="bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white shadow-lg"
onClick={() => setShowSummary(!showSummary)}
>
<ShoppingCart className="h-4 w-4 mr-2" />
Корзина ({selectedProducts.length}) {" "}
{formatCurrency(getTotalAmount())}
</Button>
</div>
)}
</div>
);
}