base commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export { CheckoutPage } from './ui/CheckoutPage'
|
||||
@@ -0,0 +1,132 @@
|
||||
import Alert from '@mui/material/Alert'
|
||||
import Box from '@mui/material/Box'
|
||||
import Button from '@mui/material/Button'
|
||||
import FormControl from '@mui/material/FormControl'
|
||||
import InputLabel from '@mui/material/InputLabel'
|
||||
import MenuItem from '@mui/material/MenuItem'
|
||||
import Select from '@mui/material/Select'
|
||||
import Stack from '@mui/material/Stack'
|
||||
import TextField from '@mui/material/TextField'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useState } from 'react'
|
||||
import { Link as RouterLink, useNavigate } from 'react-router-dom'
|
||||
import { useUnit } from 'effector-react'
|
||||
import { fetchMyCart } from '@/entities/cart/api/cart-api'
|
||||
import { createOrder } from '@/entities/order/api/order-api'
|
||||
import { fetchMyAddresses } from '@/entities/user/api/address-api'
|
||||
import { formatPriceRub } from '@/shared/lib/format-price'
|
||||
import { $user } from '@/shared/model/auth'
|
||||
|
||||
export function CheckoutPage() {
|
||||
const user = useUnit($user)
|
||||
const qc = useQueryClient()
|
||||
const navigate = useNavigate()
|
||||
const [addressId, setAddressId] = useState('')
|
||||
const [comment, setComment] = useState('')
|
||||
|
||||
const cartQuery = useQuery({
|
||||
queryKey: ['me', 'cart'],
|
||||
queryFn: fetchMyCart,
|
||||
enabled: Boolean(user),
|
||||
})
|
||||
|
||||
const addressesQuery = useQuery({
|
||||
queryKey: ['me', 'addresses'],
|
||||
queryFn: fetchMyAddresses,
|
||||
enabled: Boolean(user),
|
||||
})
|
||||
|
||||
const createMut = useMutation({
|
||||
mutationFn: () => createOrder({ addressId, comment: comment.trim() || null }),
|
||||
onSuccess: async (res) => {
|
||||
await qc.invalidateQueries({ queryKey: ['me', 'cart'] })
|
||||
navigate(`/me/orders/${res.orderId}`, { replace: true })
|
||||
},
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
return (
|
||||
<Alert severity="info">
|
||||
Чтобы оформить заказ, нужно войти. Перейдите на страницу{' '}
|
||||
<Typography component={RouterLink} to="/auth" sx={{ textDecoration: 'underline' }}>
|
||||
Вход
|
||||
</Typography>
|
||||
.
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
|
||||
const items = cartQuery.data?.items ?? []
|
||||
const total = items.reduce((s, x) => s + x.product.priceCents * x.qty, 0)
|
||||
const addresses = addressesQuery.data?.items ?? []
|
||||
|
||||
const defaultAddr = addresses.find((a) => a.isDefault)
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
Оформление заказа
|
||||
</Typography>
|
||||
|
||||
{cartQuery.isSuccess && items.length === 0 && (
|
||||
<Alert severity="info" sx={{ mb: 2 }}>
|
||||
Корзина пуста. Вернитесь в{' '}
|
||||
<Typography component={RouterLink} to="/" sx={{ textDecoration: 'underline' }}>
|
||||
каталог
|
||||
</Typography>
|
||||
.
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Stack spacing={2} sx={{ maxWidth: 720 }}>
|
||||
<FormControl size="small" fullWidth>
|
||||
<InputLabel id="addr-label">Адрес доставки</InputLabel>
|
||||
<Select
|
||||
labelId="addr-label"
|
||||
label="Адрес доставки"
|
||||
value={addressId || (defaultAddr?.id ?? '')}
|
||||
onChange={(e) => setAddressId(String(e.target.value))}
|
||||
>
|
||||
{addresses.map((a) => (
|
||||
<MenuItem key={a.id} value={a.id}>
|
||||
{(a.label?.trim() ? `${a.label}: ` : '') + a.addressLine}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
{addresses.length === 0 && (
|
||||
<Alert severity="warning">
|
||||
У вас нет адресов доставки. Добавьте адрес в{' '}
|
||||
<Typography component={RouterLink} to="/me/addresses" sx={{ textDecoration: 'underline' }}>
|
||||
кабинете
|
||||
</Typography>
|
||||
.
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
label="Комментарий к заказу (необязательно)"
|
||||
value={comment}
|
||||
onChange={(e) => setComment(e.target.value)}
|
||||
fullWidth
|
||||
multiline
|
||||
minRows={2}
|
||||
/>
|
||||
|
||||
<Typography variant="h6">Итого: {formatPriceRub(total)}</Typography>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
disabled={items.length === 0 || addresses.length === 0 || createMut.isPending}
|
||||
onClick={() => createMut.mutate()}
|
||||
>
|
||||
Создать заказ
|
||||
</Button>
|
||||
|
||||
{createMut.isError && <Alert severity="error">{(createMut.error as Error).message}</Alert>}
|
||||
</Stack>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user