Refactor: Replace wholesaler with supplier terminology and add fulfillment consumables logic

This commit is contained in:
Veronika Smirnova
2025-07-30 17:03:31 +03:00
parent e351752b09
commit 3e7ea13026
31 changed files with 3343 additions and 1538 deletions

View File

@ -1,26 +1,24 @@
"use client"
"use client";
import React from 'react'
import { Card } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import {
ShoppingCart,
Building2,
Plus,
Minus,
Eye
} from 'lucide-react'
import { SelectedProduct } from './types'
import React from "react";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { ShoppingCart, Building2, Plus, Minus, Eye } from "lucide-react";
import { SelectedProduct } from "./types";
interface CartSummaryProps {
selectedProducts: SelectedProduct[]
onQuantityChange: (productId: string, wholesalerId: string, quantity: number) => void
onRemoveProduct: (productId: string, wholesalerId: string) => void
onCreateSupply: () => void
onToggleVisibility: () => void
formatCurrency: (amount: number) => string
visible: boolean
selectedProducts: SelectedProduct[];
onQuantityChange: (
productId: string,
supplierId: string,
quantity: number
) => void;
onRemoveProduct: (productId: string, supplierId: string) => void;
onCreateSupply: () => void;
onToggleVisibility: () => void;
formatCurrency: (amount: number) => string;
visible: boolean;
}
export function CartSummary({
@ -30,36 +28,39 @@ export function CartSummary({
onCreateSupply,
onToggleVisibility,
formatCurrency,
visible
visible,
}: CartSummaryProps) {
if (!visible || selectedProducts.length === 0) {
return null
return null;
}
// Группируем товары по поставщикам
const groupedProducts = selectedProducts.reduce((acc, product) => {
if (!acc[product.wholesalerId]) {
acc[product.wholesalerId] = {
wholesaler: product.wholesalerName,
products: []
}
if (!acc[product.supplierId]) {
acc[product.supplierId] = {
supplier: product.supplierName,
products: [],
};
}
acc[product.wholesalerId].products.push(product)
return acc
}, {} as Record<string, { wholesaler: string; products: SelectedProduct[] }>)
acc[product.supplierId].products.push(product);
return acc;
}, {} as Record<string, { supplier: string; products: SelectedProduct[] }>);
const getTotalAmount = () => {
return selectedProducts.reduce((sum, product) => {
const discountedPrice = product.discount
const discountedPrice = product.discount
? product.price * (1 - product.discount / 100)
: product.price
return sum + (discountedPrice * product.selectedQuantity)
}, 0)
}
: product.price;
return sum + discountedPrice * product.selectedQuantity;
}, 0);
};
const getTotalItems = () => {
return selectedProducts.reduce((sum, product) => sum + product.selectedQuantity, 0)
}
return selectedProducts.reduce(
(sum, product) => sum + product.selectedQuantity,
0
);
};
return (
<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">
@ -72,7 +73,8 @@ export function CartSummary({
<div>
<h3 className="text-white font-bold text-lg">Корзина</h3>
<p className="text-purple-200 text-xs">
{selectedProducts.length} товаров от {Object.keys(groupedProducts).length} поставщиков
{selectedProducts.length} товаров от{" "}
{Object.keys(groupedProducts).length} поставщиков
</p>
</div>
</div>
@ -85,74 +87,99 @@ export function CartSummary({
<Eye className="h-4 w-4" />
</Button>
</div>
{/* Группировка по поставщикам */}
{Object.entries(groupedProducts).map(([wholesalerId, group]) => (
<div key={wholesalerId} className="mb-4 last:mb-0">
{Object.entries(groupedProducts).map(([supplierId, group]) => (
<div key={supplierId} 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>
<span className="text-white font-medium">{group.supplier}</span>
<Badge className="ml-2 bg-blue-500/20 text-blue-300 border-blue-500/30 text-xs">
{group.products.length} товар(ов)
</Badge>
</div>
<div className="space-y-2">
{group.products.map((product) => {
const discountedPrice = product.discount
const discountedPrice = product.discount
? product.price * (1 - product.discount / 100)
: product.price
const totalPrice = discountedPrice * product.selectedQuantity
: product.price;
const totalPrice = discountedPrice * product.selectedQuantity;
return (
<div key={`${product.wholesalerId}-${product.id}`} className="flex items-center space-x-3 bg-white/5 rounded-lg p-3">
<div
key={`${product.supplierId}-${product.id}`}
className="flex items-center space-x-3 bg-white/5 rounded-lg p-3"
>
<img
src={product.mainImage || '/api/placeholder/50/50'}
src={product.mainImage || "/api/placeholder/50/50"}
alt={product.name}
className="w-12 h-12 rounded-lg object-cover"
/>
<div className="flex-1 min-w-0">
<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>
<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"
size="sm"
onClick={() => {
const newQuantity = Math.max(0, product.selectedQuantity - 1)
const newQuantity = Math.max(
0,
product.selectedQuantity - 1
);
if (newQuantity === 0) {
onRemoveProduct(product.id, product.wholesalerId)
onRemoveProduct(product.id, product.supplierId);
} else {
onQuantityChange(product.id, product.wholesalerId, newQuantity)
onQuantityChange(
product.id,
product.supplierId,
newQuantity
);
}
}}
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-xs w-6 text-center">{product.selectedQuantity}</span>
<span className="text-white text-xs w-6 text-center">
{product.selectedQuantity}
</span>
<Button
variant="ghost"
size="sm"
onClick={() => {
onQuantityChange(
product.id,
product.wholesalerId,
Math.min(product.quantity, product.selectedQuantity + 1)
)
product.id,
product.wholesalerId,
Math.min(
product.quantity,
product.selectedQuantity + 1
)
);
}}
disabled={product.selectedQuantity >= product.quantity}
disabled={
product.selectedQuantity >= product.quantity
}
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-xs">{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)}
{formatCurrency(
product.price * product.selectedQuantity
)}
</div>
)}
</div>
@ -161,18 +188,20 @@ export function CartSummary({
<Button
variant="ghost"
size="sm"
onClick={() => onRemoveProduct(product.id, product.wholesalerId)}
onClick={() =>
onRemoveProduct(product.id, product.supplierId)
}
className="text-red-400 hover:text-red-300 hover:bg-red-500/10"
>
</Button>
</div>
)
);
})}
</div>
</div>
))}
{/* Итого */}
<div className="border-t border-white/20 pt-3 mt-4">
<div className="flex justify-between items-center">
@ -184,7 +213,7 @@ export function CartSummary({
</span>
</div>
<div className="flex space-x-2 mt-3">
<Button
<Button
variant="outline"
className="flex-1 border-purple-300/30 text-white hover:bg-white/10"
onClick={onToggleVisibility}
@ -192,7 +221,7 @@ export function CartSummary({
<Plus className="h-4 w-4 mr-2" />
Добавить еще
</Button>
<Button
<Button
className="flex-1 bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600 hover:to-emerald-600 text-white"
onClick={onCreateSupply}
>
@ -203,5 +232,5 @@ export function CartSummary({
</div>
</div>
</Card>
)
}
);
}