Vitron-Front/app/components/cart/CartItem.tsx
2026-04-29 01:44:16 +03:30

179 lines
5.4 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.

import { Check, Trash } from "lucide-react";
import { memo, useMemo } from "react";
import { QuantityControl } from "./QuantityControl";
import { formatPrice } from "../../utils/helpers";
import { CartItem as CartItemType } from "src/api/types";
import { isVideo } from "../MondrianProductList";
import { Button } from "../ui/button";
interface CartItemProps {
item: CartItemType;
onQuantityChange: (itemId: string, quantity: number) => void;
onRemoveItem: (itemId: string) => void;
isLoading: boolean;
hasBorder: boolean;
}
export const CartItem = memo(function CartItem({
item,
onQuantityChange,
onRemoveItem,
isLoading,
hasBorder,
}: CartItemProps) {
// Memoize discount calculation
const discountPercent = useMemo(() => {
if (!item.productVariant?.discountPrice || !item.productVariant?.price) {
return null;
}
return Math.round(
((Number(item.productVariant.price) -
Number(item.productVariant.discountPrice)) /
Number(item.productVariant.price)) *
100
);
}, [item.productVariant?.discountPrice, item.productVariant?.price]);
// Memoize video check
const isVideoMedia = useMemo(
() => isVideo(item.productVariant?.productImage || ""),
[item.productVariant?.productImage]
);
return (
<div
className={`flex p-4 gap-4 w-full flex-col ${hasBorder && "border-b"}`}
>
<div className="flex gap-2 w-full items-center">
{isVideoMedia ? (
<video
src={item.productVariant?.productImage}
className="rounded-[5px] w-[116px] h-[116px] object-cover"
muted
loop
autoPlay
playsInline
/>
) : (
<img
src={item.productVariant?.productImage}
alt={item.productVariant?.productTitle || ""}
className="rounded-[5px] w-[116px] h-[116px] object-cover"
loading="lazy"
/>
)}
<div className="flex flex-col gap-2">
<p className="text-B14 font-bold">
{item.productVariant?.productTitle || ""}
</p>
<p className="text-R12 text-GRAY line-clamp-1">
کد کالا: {item.productVariant?.id || ""}
</p>
</div>
</div>
<ColorSelector
color={
item.productVariant?.color?.value !== "UNSELECTED"
? item.productVariant?.color?.info?.detail || ""
: ""
}
/>
<SizeSelector
size={
item.productVariant?.size?.value !== "UNSELECTED"
? item.productVariant?.size?.info?.detail || ""
: ""
}
/>
<div className="flex w-full items-center justify-between">
<p className="text-B14 font-bold">قیمت واحد :</p>
<p className="text-B14 font-bold">
{formatPrice(item.productVariant?.price || "")} تومان
</p>
</div>
{discountPercent ? (
<div className="flex w-full items-center justify-between">
<div className="flex items-center gap-2">
<p className="text-B14 font-bold">مقدار تخفیف :</p>
<div className="bg-BLACK rounded-full text-WHITE text-R14 px-2 py-1">
{discountPercent}%
</div>
</div>
<p className="text-B14 font-bold">
{formatPrice(
(
Number(item.productVariant?.price) -
Number(item.productVariant?.discountPrice)
).toString()
)}{" "}
تومان
</p>
</div>
) : null}
{item?.productVariant?.stock && item?.productVariant?.stock > 0 ? (
<div className="flex w-full items-center justify-between">
<div className="flex items-center gap-2"></div>
<QuantityControl
isPending={isLoading}
quantity={item.quantity}
maxQuantity={item.productVariant?.stock || 0}
onIncrease={() =>
onQuantityChange(item.id || "", item.quantity + 1)
}
onDecrease={() =>
onQuantityChange(item.id || "", item.quantity - 1)
}
onRemove={() => onRemoveItem(item.id || "")}
/>
</div>
) : (
<div className="flex w-full items-center justify-between">
<p className="text-B14 font-bold">محصول در حال حاضر موجود نیست</p>
<Button
variant="dark"
className="flex items-center gap-2 bg-red-500"
size="sm"
onClick={() => onRemoveItem(item.id || "")}
>
<Trash size={16} />
</Button>
</div>
)}
</div>
);
});
// Color Selector Component
const ColorSelector = ({ color }: { color: string }) => (
<>
{color && (
<div className="flex w-full items-center justify-between">
<p className="text-B14 font-bold">رنگ :</p>
<div
className="w-10 h-10 rounded-[7px] flex items-center justify-center border border-BLACK"
style={{
backgroundColor: color,
}}
>
<Check size={24} className="text-WHITE" />
</div>
</div>
)}
</>
);
// Size Selector Component
const SizeSelector = ({ size }: { size: string }) => (
<>
{size && (
<div className="flex w-full items-center justify-between">
<p className="text-B14 font-bold">سایز :</p>
<p className="text-BLACK text-R12">{size}</p>
</div>
)}
</>
);