165 lines
4.1 KiB
TypeScript
165 lines
4.1 KiB
TypeScript
|
|
import { useState } from 'react';
|
|||
|
|
import styled from 'styled-components';
|
|||
|
|
import { getProductAmount } from '../../utils/product';
|
|||
|
|
import type { Product } from '../../types/cart';
|
|||
|
|
|
|||
|
|
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);
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<Item $processing={isProcessing}>
|
|||
|
|
<ItemImage type="button" onClick={onOpen}>
|
|||
|
|
<img src={product.image} alt="" />
|
|||
|
|
</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 && (
|
|||
|
|
<Dropdown>
|
|||
|
|
<ul>
|
|||
|
|
<li>
|
|||
|
|
<button type="button" onClick={onReplace}>
|
|||
|
|
Заменить
|
|||
|
|
</button>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<button type="button" onClick={onDelete}>
|
|||
|
|
Удалить
|
|||
|
|
</button>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
</Dropdown>
|
|||
|
|
)}
|
|||
|
|
</MenuWrapper>
|
|||
|
|
</Item>
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const Item = styled.li<{ $processing: boolean }>`
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 16px 0;
|
|||
|
|
border-bottom: 1px solid #f0f0f0;
|
|||
|
|
position: relative;
|
|||
|
|
transition: opacity 0.4s, transform 0.4s;
|
|||
|
|
opacity: ${({ $processing }) => ($processing ? 0.5 : 1)};
|
|||
|
|
pointer-events: ${({ $processing }) => ($processing ? 'none' : 'auto')};
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
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`
|
|||
|
|
flex: 1;
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
const ItemName = styled.div`
|
|||
|
|
font-size: 15px;
|
|||
|
|
color: ${({ theme }) => theme.colors.darkGreen};
|
|||
|
|
margin-bottom: 4px;
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
const ItemPrice = styled.div`
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: ${({ theme }) => theme.colors.gray};
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
const MenuWrapper = styled.div`
|
|||
|
|
position: relative;
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
const MenuButton = styled.button`
|
|||
|
|
background: none;
|
|||
|
|
border: none;
|
|||
|
|
color: #b0b0b0;
|
|||
|
|
cursor: pointer;
|
|||
|
|
padding: 4px 8px;
|
|||
|
|
font-size: 20px;
|
|||
|
|
letter-spacing: 2px;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
transition: 0.2s;
|
|||
|
|
|
|||
|
|
&:hover {
|
|||
|
|
background: #f3f4f6;
|
|||
|
|
color: ${({ theme }) => theme.colors.darkGreen};
|
|||
|
|
}
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
const Dropdown = styled.div`
|
|||
|
|
position: absolute;
|
|||
|
|
right: 0;
|
|||
|
|
top: 100%;
|
|||
|
|
background: #ffffff;
|
|||
|
|
border: 1px solid #eee;
|
|||
|
|
border-radius: 8px;
|
|||
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|||
|
|
min-width: 150px;
|
|||
|
|
padding: 6px 0;
|
|||
|
|
z-index: 10;
|
|||
|
|
margin-top: 4px;
|
|||
|
|
|
|||
|
|
ul {
|
|||
|
|
list-style: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
button {
|
|||
|
|
width: 100%;
|
|||
|
|
padding: 10px 16px;
|
|||
|
|
font-size: 14px;
|
|||
|
|
color: ${({ theme }) => theme.colors.darkGreen};
|
|||
|
|
cursor: pointer;
|
|||
|
|
transition: 0.2s;
|
|||
|
|
background: transparent;
|
|||
|
|
border: 0;
|
|||
|
|
text-align: left;
|
|||
|
|
|
|||
|
|
&:hover {
|
|||
|
|
background: #f3f4f6;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
`;
|