|
|
|
|
@ -1,13 +1,22 @@
|
|
|
|
|
import { Fragment, useCallback, useMemo, useState } from 'react'
|
|
|
|
|
import { Fragment, useCallback, useEffect, useMemo, useState } from 'react'
|
|
|
|
|
import {
|
|
|
|
|
Avatar,
|
|
|
|
|
Box,
|
|
|
|
|
Button,
|
|
|
|
|
Divider,
|
|
|
|
|
IconButton,
|
|
|
|
|
List,
|
|
|
|
|
ListItem,
|
|
|
|
|
ListItemIcon,
|
|
|
|
|
ListItemText,
|
|
|
|
|
Paper,
|
|
|
|
|
Stack,
|
|
|
|
|
styled,
|
|
|
|
|
Table,
|
|
|
|
|
TableBody,
|
|
|
|
|
TableCell,
|
|
|
|
|
TableContainer,
|
|
|
|
|
TableRow,
|
|
|
|
|
Typography,
|
|
|
|
|
} from '@mui/material'
|
|
|
|
|
import { AddCircleOutline, RemoveCircleOutline } from '@mui/icons-material'
|
|
|
|
|
@ -26,6 +35,13 @@ const getText = (str?: string): string => {
|
|
|
|
|
return (str?.length || 0) <= MAX_LEN_STR ? str || '' : str?.substring(0, MAX_LEN_STR) + '...'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const StyledTableRow = styled(TableRow)(({ theme }) => ({
|
|
|
|
|
cursor: 'pointer',
|
|
|
|
|
'&:hover': {
|
|
|
|
|
backgroundColor: theme.palette.action.hover,
|
|
|
|
|
},
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
type LasFetchType = 'addProduct' | 'deleteProduct' | 'buyProducts' | 'none'
|
|
|
|
|
|
|
|
|
|
export const BasketPage = withProtection(() => {
|
|
|
|
|
@ -52,6 +68,10 @@ export const BasketPage = withProtection(() => {
|
|
|
|
|
|
|
|
|
|
const dispatch = useAppDispatch()
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
dispatch(basket.fetch.basket())
|
|
|
|
|
}, [dispatch])
|
|
|
|
|
|
|
|
|
|
const handleUpdateQuantity = useCallback(
|
|
|
|
|
(productId: number, quantity: number) => {
|
|
|
|
|
if (quantity > 0) {
|
|
|
|
|
@ -86,6 +106,7 @@ export const BasketPage = withProtection(() => {
|
|
|
|
|
toast.error(error || 'Не известная ошибка при аутентификации пользователя', {
|
|
|
|
|
toastId: 'error-toast',
|
|
|
|
|
})
|
|
|
|
|
dispatch(basket.action.clearError())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (loading && lasFetch === 'buyProducts') {
|
|
|
|
|
@ -104,65 +125,83 @@ export const BasketPage = withProtection(() => {
|
|
|
|
|
Продуктовая корзина
|
|
|
|
|
</Typography>
|
|
|
|
|
</Stack>
|
|
|
|
|
<List component="nav" aria-label="cart items">
|
|
|
|
|
<Fragment>
|
|
|
|
|
{sortedProducts.length ? (
|
|
|
|
|
<Stack direction="row" alignItems="center" spacing={2} sx={{ pb: 2 }}>
|
|
|
|
|
<Typography variant="h6" gutterBottom>
|
|
|
|
|
{`Заказ №: ${1}`}
|
|
|
|
|
</Typography>
|
|
|
|
|
</Stack>
|
|
|
|
|
) : (
|
|
|
|
|
<></>
|
|
|
|
|
)}
|
|
|
|
|
{sortedProducts?.map(product => (
|
|
|
|
|
<ListItem key={product.id}>
|
|
|
|
|
<ListItemText
|
|
|
|
|
onClick={() => handleProduct(product.id)}
|
|
|
|
|
primary={`Название: ${getText(getProduct(product.id)?.name)}`}
|
|
|
|
|
/>
|
|
|
|
|
<ListItemText
|
|
|
|
|
onClick={() => handleProduct(product.id)}
|
|
|
|
|
primary={`Цена: ${Number(product.cost) * product.user_count} ₽`}
|
|
|
|
|
/>
|
|
|
|
|
<ListItemText
|
|
|
|
|
onClick={() => handleProduct(product.id)}
|
|
|
|
|
primary={`На складе: ${getProduct(product.id)?.count} `}
|
|
|
|
|
/>
|
|
|
|
|
<ListItemText
|
|
|
|
|
onClick={() => handleProduct(product.id)}
|
|
|
|
|
primary={`${product.user_count} шт.`}
|
|
|
|
|
/>
|
|
|
|
|
<IconButton
|
|
|
|
|
edge="start"
|
|
|
|
|
aria-label="add"
|
|
|
|
|
onClick={() => handleUpdateQuantity(product.id, 1)}
|
|
|
|
|
>
|
|
|
|
|
<AddCircleOutline />
|
|
|
|
|
</IconButton>
|
|
|
|
|
<IconButton
|
|
|
|
|
edge="start"
|
|
|
|
|
aria-label="remove"
|
|
|
|
|
onClick={() => handleUpdateQuantity(product.id, -1)}
|
|
|
|
|
>
|
|
|
|
|
<RemoveCircleOutline />
|
|
|
|
|
</IconButton>
|
|
|
|
|
</ListItem>
|
|
|
|
|
))}
|
|
|
|
|
<Box sx={{ pb: 3 }}>
|
|
|
|
|
<Divider />
|
|
|
|
|
</Box>
|
|
|
|
|
{sortedProducts.length ? (
|
|
|
|
|
<Button color="success" variant="contained" onClick={handleBuy}>
|
|
|
|
|
{'КУПИТЬ'}
|
|
|
|
|
</Button>
|
|
|
|
|
) : (
|
|
|
|
|
<Typography variant="button" sx={{ fontSize: 16, pt: 2, pb: 2 }}>
|
|
|
|
|
Корзина пуста
|
|
|
|
|
</Typography>
|
|
|
|
|
)}
|
|
|
|
|
</Fragment>
|
|
|
|
|
</List>
|
|
|
|
|
<TableContainer component={Paper}>
|
|
|
|
|
<Table>
|
|
|
|
|
<TableBody>
|
|
|
|
|
{products.map(product => {
|
|
|
|
|
const prod = getProduct(product.id)
|
|
|
|
|
if (!prod) return null
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<StyledTableRow
|
|
|
|
|
key={product.id}
|
|
|
|
|
onClick={() => handleProduct(product.id)}
|
|
|
|
|
>
|
|
|
|
|
{/* Квадратное изображение */}
|
|
|
|
|
<TableCell sx={{ width: 64, padding: '8px' }}>
|
|
|
|
|
<Avatar
|
|
|
|
|
variant="square"
|
|
|
|
|
src={prod.picture_url || ''}
|
|
|
|
|
alt={prod.name || 'Товар'}
|
|
|
|
|
sx={{
|
|
|
|
|
width: 48,
|
|
|
|
|
height: 48,
|
|
|
|
|
objectFit: 'cover',
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</TableCell>
|
|
|
|
|
|
|
|
|
|
{/* Название */}
|
|
|
|
|
<TableCell>{getText(prod.name)}</TableCell>
|
|
|
|
|
|
|
|
|
|
{/* Цена */}
|
|
|
|
|
<TableCell>{`Цена: ${Number(product.cost) * product.user_count} ₽`}</TableCell>
|
|
|
|
|
|
|
|
|
|
{/* На складе */}
|
|
|
|
|
<TableCell>{`Доступно: ${prod.count}`}</TableCell>
|
|
|
|
|
|
|
|
|
|
{/* Количество у пользователя */}
|
|
|
|
|
<TableCell>{`${product.user_count} шт.`}</TableCell>
|
|
|
|
|
|
|
|
|
|
{/* Кнопки управления */}
|
|
|
|
|
<TableCell padding="none" sx={{ width: 'auto' }}>
|
|
|
|
|
<IconButton
|
|
|
|
|
onClick={e => {
|
|
|
|
|
e.stopPropagation() // предотвращает срабатывание onClick строки
|
|
|
|
|
handleUpdateQuantity(product.id, 1)
|
|
|
|
|
}}
|
|
|
|
|
size="small"
|
|
|
|
|
>
|
|
|
|
|
<AddCircleOutline />
|
|
|
|
|
</IconButton>
|
|
|
|
|
<IconButton
|
|
|
|
|
onClick={e => {
|
|
|
|
|
e.stopPropagation()
|
|
|
|
|
handleUpdateQuantity(product.id, -1)
|
|
|
|
|
}}
|
|
|
|
|
size="small"
|
|
|
|
|
>
|
|
|
|
|
<RemoveCircleOutline />
|
|
|
|
|
</IconButton>
|
|
|
|
|
</TableCell>
|
|
|
|
|
</StyledTableRow>
|
|
|
|
|
)
|
|
|
|
|
})}
|
|
|
|
|
</TableBody>
|
|
|
|
|
</Table>
|
|
|
|
|
</TableContainer>
|
|
|
|
|
<Box sx={{ pb: 3 }}>
|
|
|
|
|
<Divider />
|
|
|
|
|
</Box>
|
|
|
|
|
{sortedProducts.length ? (
|
|
|
|
|
<Button color="success" variant="contained" onClick={handleBuy}>
|
|
|
|
|
{`КУПИТЬ ЗА ${products.reduce((total, product) => total + Number(product.cost) * product.user_count, 0)} ₽`}
|
|
|
|
|
</Button>
|
|
|
|
|
) : (
|
|
|
|
|
<Typography variant="button" sx={{ fontSize: 16, pt: 2, pb: 2 }}>
|
|
|
|
|
Корзина пуста
|
|
|
|
|
</Typography>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
|