142 lines
5.1 KiB
TypeScript
142 lines
5.1 KiB
TypeScript
'use client';
|
|
|
|
import { colorHexMap } from '@/components/products/utils/colorUtils';
|
|
import { Button } from '@/components/ui/Button';
|
|
import { Text } from '@/components/ui/Typography';
|
|
import { useTranslation } from '@/lib/hooks/useTranslation';
|
|
import { useCart } from 'components/cart/cart-context';
|
|
import Price from 'components/price';
|
|
import { CartItem } from 'lib/shopify/types';
|
|
import { Trash2 } from 'lucide-react';
|
|
import Image from 'next/image';
|
|
import { QuantityControls } from './QuantityControls';
|
|
|
|
interface CartProductItemProps {
|
|
item: CartItem;
|
|
onUpdate: (merchandiseId: string, updateType: 'plus' | 'minus' | 'delete', itemId?: string) => void;
|
|
isPending: boolean;
|
|
isInBox?: boolean;
|
|
boxGroupId?: string;
|
|
}
|
|
|
|
export function CartProductItem({ item, onUpdate, isPending, isInBox = false, boxGroupId }: CartProductItemProps) {
|
|
const { t } = useTranslation();
|
|
const { cart } = useCart();
|
|
|
|
// Check if this item has a color option
|
|
const colorOption = item.merchandise.selectedOptions.find(option =>
|
|
option.name.toLowerCase() === 'color' ||
|
|
option.name.toLowerCase() === 'colour' ||
|
|
option.name.toLowerCase() === 'boja'
|
|
);
|
|
|
|
// Get the color hex code from the color name if it exists
|
|
const colorHex = colorOption
|
|
? colorHexMap[colorOption.value.toLowerCase()] || colorOption.value
|
|
: null;
|
|
|
|
// Get the unique ID of this cart item
|
|
const itemId = item.id;
|
|
|
|
// Handle quantity changes
|
|
const handleIncrease = () => onUpdate(item.merchandise.id, 'plus', itemId);
|
|
const handleDecrease = () => onUpdate(item.merchandise.id, 'minus', itemId);
|
|
|
|
// Enhanced delete handler
|
|
const handleDelete = () => {
|
|
// Basic delete operation for this item
|
|
onUpdate(item.merchandise.id, 'delete', itemId);
|
|
|
|
// Special handling for box items
|
|
if (isInBox && boxGroupId && cart) {
|
|
// Find all items in this box group
|
|
const boxItems = cart.lines.filter(line => {
|
|
const attrs = line.attributes || [];
|
|
const itemBoxGroupId = attrs.find(attr => attr.key === '_box_group_id')?.value;
|
|
const itemBoxType = attrs.find(attr => attr.key === '_box_type')?.value;
|
|
return itemBoxGroupId === boxGroupId && itemBoxType === 'item' && line.id !== itemId;
|
|
});
|
|
|
|
// If this is the last item (only 1 left - the one we're deleting), also delete the box container
|
|
if (boxItems.length === 0) {
|
|
// Find the box container
|
|
const boxContainer = cart.lines.find(line => {
|
|
const attrs = line.attributes || [];
|
|
const containerBoxGroupId = attrs.find(attr => attr.key === '_box_group_id')?.value;
|
|
const containerBoxType = attrs.find(attr => attr.key === '_box_type')?.value;
|
|
return containerBoxGroupId === boxGroupId && containerBoxType === 'container';
|
|
});
|
|
|
|
// Delete the box container too
|
|
if (boxContainer && boxContainer.id) {
|
|
onUpdate(boxContainer.merchandise.id, 'delete', boxContainer.id);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className={`flex flex-wrap md:flex-nowrap items-start ${!isInBox ? 'border-b pb-6' : 'pb-4'}`}>
|
|
{/* Product Image */}
|
|
<div className="relative h-20 w-20 flex-shrink-0 overflow-hidden">
|
|
<Image
|
|
src={item.merchandise.product.featuredImage?.url || ''}
|
|
alt={item.merchandise.product.title}
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
|
|
{/* Product Details */}
|
|
<div className="flex-1 pl-4 min-w-0">
|
|
<div className="flex flex-col">
|
|
<Text weight={isInBox ? 'regular' : 'semibold'} className="pr-2 break-words">
|
|
{item.merchandise.product.title}
|
|
</Text>
|
|
|
|
{/* Show color indicator if color is available */}
|
|
{colorHex && (
|
|
<div className="flex items-center mt-1">
|
|
<div
|
|
className="w-4 h-4 rounded-full"
|
|
style={{ backgroundColor: colorHex }}
|
|
aria-label={`${colorOption?.value || 'Unknown'}`}
|
|
/>
|
|
<Text size="xs" color="muted" as="span" className="ml-2">
|
|
{colorOption?.value || ''}
|
|
</Text>
|
|
</div>
|
|
)}
|
|
|
|
<Price
|
|
amount={item.cost.totalAmount.amount}
|
|
currencyCode={item.cost.totalAmount.currencyCode}
|
|
className="text-sm mt-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Quantity Controls */}
|
|
<div className="flex items-center ml-auto mt-2 md:mt-0">
|
|
<div className="mr-4">
|
|
<QuantityControls
|
|
quantity={item.quantity}
|
|
onIncrease={handleIncrease}
|
|
onDecrease={handleDecrease}
|
|
isDisabled={isPending}
|
|
minQuantity={1}
|
|
/>
|
|
</div>
|
|
<Button
|
|
onClick={handleDelete}
|
|
variant="default"
|
|
className="p-0 h-auto border-0 bg-transparent hover:bg-transparent text-gray-500 hover:text-red-500"
|
|
disabled={isPending}
|
|
aria-label={t('cart.remove')}
|
|
>
|
|
<Trash2 size={20} />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|