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-04 15:57:54 +00:00
|
|
|
|
import {reachGoal} from "../../hooks/useYM";
|
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(() => {
|
2026-09-04 15:57:54 +00:00
|
|
|
|
if (isMenuOpen) {
|
|
|
|
|
|
reachGoal('ac_product_replacement_menu_' + product.name);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [product.name, isMenuOpen])
|
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)} × {Math.round(product.price * 100) / 100} ₽
|
|
|
|
|
|
</ItemPrice>
|
|
|
|
|
|
</ItemDetails>
|
|
|
|
|
|
|
|
|
|
|
|
<MenuWrapper>
|
|
|
|
|
|
<MenuButton
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => setIsMenuOpen(value => !value)}
|
|
|
|
|
|
>
|
|
|
|
|
|
⋮
|
|
|
|
|
|
</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`
|
2026-09-05 18:48:01 +00:00
|
|
|
|
height: 100svh;
|
2026-08-30 11:47:34 +00:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
`;
|