base commit

This commit is contained in:
@kirill.komarov
2026-04-29 20:23:30 +05:00
parent f26223091a
commit 123d86091d
25 changed files with 525 additions and 159 deletions
+95 -47
View File
@@ -7,6 +7,7 @@ import Button from '@mui/material/Button'
import Divider from '@mui/material/Divider'
import IconButton from '@mui/material/IconButton'
import Stack from '@mui/material/Stack'
import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useUnit } from 'effector-react'
@@ -62,57 +63,104 @@ export function CartPage() {
{items.length > 0 && (
<Stack spacing={2}>
{items.map((x) => (
<Box
key={x.id}
sx={{
border: 1,
borderColor: 'divider',
borderRadius: 2,
p: 2,
bgcolor: 'background.paper',
}}
>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2} alignItems={{ sm: 'center' }}>
<Box sx={{ flexGrow: 1 }}>
<Typography sx={{ fontWeight: 700 }}>{x.product.title}</Typography>
<Typography color="text.secondary" variant="body2">
{formatPriceRub(x.product.priceCents)} · {x.qty} шт.
</Typography>
{items.map((x) =>
(() => {
const available = x.product.inStock ? x.product.quantity : 1
const canInc = x.qty < available
const over = x.qty > available
return (
<Box
key={x.id}
sx={{
border: 1,
borderColor: over ? 'error.light' : 'divider',
borderRadius: 2,
p: 2,
bgcolor: over ? 'error.50' : 'background.paper',
}}
>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2} sx={{ alignItems: { sm: 'center' } }}>
<Box sx={{ flexGrow: 1 }}>
<Typography sx={{ fontWeight: 700 }}>{x.product.title}</Typography>
<Typography color="text.secondary" variant="body2">
{formatPriceRub(x.product.priceCents)} · {x.qty} шт. · Доступно: {available}
</Typography>
{!x.product.inStock && (
<Typography color="text.secondary" variant="caption">
Под заказ доставка после изготовления
</Typography>
)}
{over && (
<Typography color="error" variant="caption" sx={{ display: 'block', mt: 0.5 }}>
Недостаточно товара. Уменьшите количество до {available}.
</Typography>
)}
</Box>
<Stack
direction="row"
spacing={0.5}
sx={{
bgcolor: 'background.default',
borderRadius: 999,
px: 0.75,
height: 40,
alignItems: 'center',
}}
>
<IconButton
onClick={() => qtyMut.mutate({ id: x.id, qty: Math.max(0, x.qty - 1) })}
disabled={qtyMut.isPending}
aria-label="Уменьшить количество"
size="small"
sx={{ width: 32, height: 32 }}
>
<RemoveIcon />
</IconButton>
<Typography
sx={{
minWidth: 28,
textAlign: 'center',
lineHeight: 1,
fontWeight: 700,
fontVariantNumeric: 'tabular-nums',
}}
>
{x.qty}
</Typography>
<Tooltip title={!canInc ? `Доступно: ${available}` : 'Увеличить количество'}>
<span>
<IconButton
onClick={() => qtyMut.mutate({ id: x.id, qty: x.qty + 1 })}
disabled={qtyMut.isPending || !canInc}
aria-label="Увеличить количество"
size="small"
sx={{ width: 32, height: 32 }}
>
<AddIcon />
</IconButton>
</span>
</Tooltip>
<IconButton
onClick={() => removeMut.mutate(x.id)}
disabled={removeMut.isPending}
aria-label="Удалить"
size="small"
sx={{ width: 32, height: 32 }}
>
<DeleteOutlineOutlinedIcon />
</IconButton>
</Stack>
</Stack>
</Box>
<Stack direction="row" spacing={1} alignItems="center">
<IconButton
onClick={() => qtyMut.mutate({ id: x.id, qty: Math.max(0, x.qty - 1) })}
disabled={qtyMut.isPending}
aria-label="Уменьшить количество"
>
<RemoveIcon />
</IconButton>
<Typography sx={{ minWidth: 24, textAlign: 'center' }}>{x.qty}</Typography>
<IconButton
onClick={() => qtyMut.mutate({ id: x.id, qty: x.qty + 1 })}
disabled={qtyMut.isPending}
aria-label="Увеличить количество"
>
<AddIcon />
</IconButton>
<IconButton
onClick={() => removeMut.mutate(x.id)}
disabled={removeMut.isPending}
aria-label="Удалить"
>
<DeleteOutlineOutlinedIcon />
</IconButton>
</Stack>
</Stack>
</Box>
))}
)
})(),
)}
<Divider />
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2} alignItems={{ sm: 'center' }}>
<Stack direction={{ xs: 'column', sm: 'row' }} spacing={2} sx={{ alignItems: { sm: 'center' } }}>
<Typography variant="h6" sx={{ flexGrow: 1 }}>
Итого: {formatPriceRub(total)}
</Typography>