marketing/src/components/Cart/CartItem.tsx

194 lines
4.9 KiB
TypeScript
Raw Normal View History

2026-09-03 10:50:12 +00:00
import {useEffect, useState} from 'react';
2026-08-24 10:07:16 +00:00
import styled from 'styled-components';
2026-08-30 11:47:34 +00:00
import {getProductAmount} from '../../utils/product';
import type {Product} from '../../types/cart';
2026-09-03 10:50:12 +00:00
import ym from "react-yandex-metrika";
2026-08-24 10:07:16 +00:00
interface CartItemProps {
product: Product;
isProcessing: boolean;
onOpen: () => void;
onReplace: () => void;
onDelete: () => void;
}
export function CartItem({
product,
isProcessing,
onOpen,
onReplace,
onDelete,
}: CartItemProps) {
const [isMenuOpen, setIsMenuOpen] = useState(false);
2026-09-03 10:50:12 +00:00
useEffect(() => {
ym('reachGoal', 'ac_product_replacement_menu_' + product.name);
}, [product.name])
2026-08-24 10:07:16 +00:00
return (
<Item $processing={isProcessing}>
<ItemImage type="button" onClick={onOpen}>
2026-08-30 11:47:34 +00:00
<img src={product.image} alt=""/>
2026-08-24 10:07:16 +00:00
</ItemImage>
<ItemDetails>
<ItemName>{product.name}</ItemName>
<ItemPrice>
{getProductAmount(product)} &times; {Math.round(product.price * 100) / 100}
</ItemPrice>
</ItemDetails>
<MenuWrapper>
<MenuButton
type="button"
onClick={() => setIsMenuOpen(value => !value)}
>
&#8942;
</MenuButton>
{isMenuOpen && (
2026-08-30 11:47:34 +00:00
<>
<Overlay onClick={() => setIsMenuOpen(false)}>
</Overlay>
<Dropdown>
<ul>
<li>
<button type="button" onClick={onReplace}>
Заменить
</button>
</li>
<li>
<button type="button" onClick={onDelete}>
Удалить
</button>
</li>
</ul>
</Dropdown>
</>
2026-08-24 10:07:16 +00:00
)}
</MenuWrapper>
</Item>
);
}
const Item = styled.li<{ $processing: boolean }>`
display: flex;
2026-08-30 11:47:34 +00:00
flex-direction: row;
align-items: stretch;
2026-08-24 10:07:16 +00:00
padding: 16px 0;
2026-08-31 08:55:33 +00:00
border-bottom: 1px solid #E7EDE7;
2026-08-24 10:07:16 +00:00
position: relative;
transition: opacity 0.4s, transform 0.4s;
2026-08-30 11:47:34 +00:00
opacity: ${({$processing}) => ($processing ? 0.5 : 1)};
pointer-events: ${({$processing}) => ($processing ? 'none' : 'auto')};
2026-08-24 10:07:16 +00:00
`;
const ItemImage = styled.button`
width: 72px;
height: 65px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16px;
flex-shrink: 0;
position: relative;
overflow: hidden;
border: 0;
background: transparent;
cursor: pointer;
img {
max-width: 100%;
max-height: 100%;
}
`;
const ItemDetails = styled.div`
2026-08-30 11:47:34 +00:00
flex: 1 1 100%;
display: flex;
justify-content: space-between;
flex-direction: column;
2026-08-24 10:07:16 +00:00
`;
const ItemName = styled.div`
font-size: 15px;
2026-08-30 11:47:34 +00:00
color: ${({theme}) => theme.colors.darkGreen};
2026-08-24 10:07:16 +00:00
margin-bottom: 4px;
`;
const ItemPrice = styled.div`
font-size: 14px;
2026-09-02 11:17:13 +00:00
color: ${({theme}) => theme.colors.darkGreen};
2026-08-24 10:07:16 +00:00
`;
const MenuWrapper = styled.div`
position: relative;
2026-08-30 11:47:34 +00:00
width: 26px;
display: flex;
align-self: flex-start;
2026-08-24 10:07:16 +00:00
`;
const MenuButton = styled.button`
background: none;
border: none;
2026-08-31 08:55:33 +00:00
color: #CEDFD0;
2026-08-24 10:07:16 +00:00
cursor: pointer;
padding: 4px 8px;
font-size: 20px;
letter-spacing: 2px;
border-radius: 4px;
transition: 0.2s;
2026-08-30 11:47:34 +00:00
position: absolute;
top: 0; right: 0;
2026-08-24 10:07:16 +00:00
&:hover {
background: #f3f4f6;
2026-08-30 11:47:34 +00:00
color: ${({theme}) => theme.colors.darkGreen};
2026-08-24 10:07:16 +00:00
}
`;
2026-08-30 11:47:34 +00:00
const Overlay = styled.div`
position: fixed;
display: flex;
inset: 0;
background-color: rgba(0, 0, 0, 0);
justify-content: center;
align-items: center;
z-index: 9;
2026-09-02 06:41:12 +00:00
overflow: auto;
2026-08-30 11:47:34 +00:00
`;
2026-08-24 10:07:16 +00:00
const Dropdown = styled.div`
position: absolute;
right: 0;
top: 100%;
background: #ffffff;
border-radius: 8px;
2026-08-30 11:47:34 +00:00
box-shadow: 0 11px 29px rgba(0, 0, 0, 0.06);
2026-08-24 10:07:16 +00:00
min-width: 150px;
2026-08-30 11:47:34 +00:00
padding: 10px;
2026-08-24 10:07:16 +00:00
z-index: 10;
margin-top: 4px;
ul {
list-style: none;
}
button {
width: 100%;
padding: 10px 16px;
font-size: 14px;
2026-08-30 11:47:34 +00:00
color: ${({theme}) => theme.colors.darkGreen};
2026-08-24 10:07:16 +00:00
cursor: pointer;
transition: 0.2s;
background: transparent;
border: 0;
2026-08-30 11:47:34 +00:00
border-radius: 8px;
text-align: center;
2026-08-24 10:07:16 +00:00
&:hover {
2026-08-30 11:47:34 +00:00
background: #5EA12D;
color: #fff;
2026-08-24 10:07:16 +00:00
}
}
`;