marketing/src/components/Cart/CartItem.tsx
2026-08-30 14:47:34 +03:00

189 lines
4.7 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 {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)} &times; {Math.round(product.price * 100) / 100}
</ItemPrice>
</ItemDetails>
<MenuWrapper>
<MenuButton
type="button"
onClick={() => setIsMenuOpen(value => !value)}
>
&#8942;
</MenuButton>
{isMenuOpen && (
<>
<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>
</>
)}
</MenuWrapper>
</Item>
);
}
const Item = styled.li<{ $processing: boolean }>`
display: flex;
flex-direction: row;
align-items: stretch;
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 1 100%;
display: flex;
justify-content: space-between;
flex-direction: column;
`;
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;
width: 26px;
display: flex;
align-self: flex-start;
`;
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;
position: absolute;
top: 0; right: 0;
&:hover {
background: #f3f4f6;
color: ${({theme}) => theme.colors.darkGreen};
}
`;
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;
`;
const Dropdown = styled.div`
position: absolute;
right: 0;
top: 100%;
background: #ffffff;
border-radius: 8px;
box-shadow: 0 11px 29px rgba(0, 0, 0, 0.06);
min-width: 150px;
padding: 10px;
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;
border-radius: 8px;
text-align: center;
&:hover {
background: #5EA12D;
color: #fff;
}
}
`;