base commit
This commit is contained in:
@@ -2,9 +2,9 @@ import type { ReactNode } from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import ChatOutlinedIcon from '@mui/icons-material/ChatOutlined'
|
||||
import LocalShippingOutlinedIcon from '@mui/icons-material/LocalShippingOutlined'
|
||||
import MenuOutlinedIcon from '@mui/icons-material/MenuOutlined'
|
||||
import PlaceOutlinedIcon from '@mui/icons-material/PlaceOutlined'
|
||||
import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined'
|
||||
import TuneOutlinedIcon from '@mui/icons-material/TuneOutlined'
|
||||
import Alert from '@mui/material/Alert'
|
||||
import Badge from '@mui/material/Badge'
|
||||
import Box from '@mui/material/Box'
|
||||
@@ -67,6 +67,9 @@ export function MeLayoutPage() {
|
||||
if (!user) {
|
||||
return <Alert severity="info">Нужно войти. Перейдите на страницу «Вход».</Alert>
|
||||
}
|
||||
if (user.isAdmin) {
|
||||
return <Navigate to="/admin" replace />
|
||||
}
|
||||
|
||||
const activeTo =
|
||||
navItems.find((x) => location.pathname === x.to)?.to ??
|
||||
@@ -74,8 +77,8 @@ export function MeLayoutPage() {
|
||||
null
|
||||
|
||||
const nav = (
|
||||
<Box sx={{ width: 280, maxWidth: '85vw' }}>
|
||||
<Box sx={{ p: 2 }}>
|
||||
<Box sx={{ width: 300, maxWidth: '88vw', py: 1 }}>
|
||||
<Box sx={{ px: 2, py: 2, mx: 1, borderRadius: 2, bgcolor: 'action.hover' }}>
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
|
||||
Кабинет
|
||||
</Typography>
|
||||
@@ -83,12 +86,23 @@ export function MeLayoutPage() {
|
||||
{user.name?.trim() || user.email}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Divider />
|
||||
<Divider sx={{ my: 1 }} />
|
||||
<List disablePadding>
|
||||
{navItems.map((i) => (
|
||||
<ListItemButton
|
||||
key={i.to}
|
||||
selected={activeTo === i.to}
|
||||
sx={{
|
||||
mx: 1,
|
||||
mb: 0.5,
|
||||
borderRadius: 2,
|
||||
'&.Mui-selected': {
|
||||
bgcolor: 'primary.50',
|
||||
},
|
||||
'&.Mui-selected:hover': {
|
||||
bgcolor: 'primary.100',
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
navigate(i.to)
|
||||
setMobileOpen(false)
|
||||
@@ -119,14 +133,38 @@ export function MeLayoutPage() {
|
||||
{isMobile ? (
|
||||
<>
|
||||
<Stack direction="row" spacing={1} sx={{ width: '100%', alignItems: 'center' }}>
|
||||
<IconButton onClick={() => setMobileOpen(true)} aria-label="Открыть меню профиля">
|
||||
<MenuOutlinedIcon />
|
||||
<IconButton
|
||||
onClick={() => setMobileOpen(true)}
|
||||
aria-label="Открыть меню кабинета"
|
||||
sx={{
|
||||
borderRadius: 2,
|
||||
border: 1,
|
||||
borderColor: 'divider',
|
||||
bgcolor: 'background.paper',
|
||||
}}
|
||||
>
|
||||
<TuneOutlinedIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h5" sx={{ fontWeight: 700 }}>
|
||||
Профиль
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Drawer open={mobileOpen} onClose={() => setMobileOpen(false)} ModalProps={{ keepMounted: true }}>
|
||||
<Drawer
|
||||
open={mobileOpen}
|
||||
onClose={() => setMobileOpen(false)}
|
||||
anchor="right"
|
||||
ModalProps={{ keepMounted: true }}
|
||||
slotProps={{
|
||||
paper: {
|
||||
sx: {
|
||||
borderTopLeftRadius: 16,
|
||||
borderBottomLeftRadius: 16,
|
||||
borderLeft: 1,
|
||||
borderColor: 'divider',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{nav}
|
||||
</Drawer>
|
||||
</>
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Link as RouterLink } from 'react-router-dom'
|
||||
import { fetchMyOrder, postOrderMessage } from '@/entities/order/api/order-api'
|
||||
import { fetchMyConversations, markOrderMessagesRead } from '@/entities/user/api/messages-api'
|
||||
import { orderStatusLabelRu } from '@/shared/lib/order-status-labels'
|
||||
import { RichTextMessageContent } from '@/shared/ui/RichTextMessageContent'
|
||||
import { RichTextMessageEditor } from '@/shared/ui/RichTextMessageEditor'
|
||||
|
||||
export function MessagesPage() {
|
||||
@@ -57,6 +58,7 @@ export function MessagesPage() {
|
||||
})
|
||||
|
||||
const order = orderQuery.data?.item
|
||||
const canSendMessage = text.replace(/<[^>]*>/g, ' ').trim().length > 0
|
||||
|
||||
return (
|
||||
<Box>
|
||||
@@ -166,12 +168,15 @@ export function MessagesPage() {
|
||||
bgcolor: m.authorType === 'admin' ? 'grey.100' : 'primary.50',
|
||||
border: 1,
|
||||
borderColor: 'divider',
|
||||
alignSelf: m.authorType === 'admin' ? 'flex-start' : 'flex-end',
|
||||
width: 'fit-content',
|
||||
maxWidth: '85%',
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{m.authorType === 'admin' ? 'Админ' : 'Вы'} · {new Date(m.createdAt).toLocaleString()}
|
||||
</Typography>
|
||||
<Typography sx={{ whiteSpace: 'pre-wrap' }}>{m.text}</Typography>
|
||||
<RichTextMessageContent value={m.text} />
|
||||
</Box>
|
||||
))}
|
||||
{order.messages.length === 0 && <Typography color="text.secondary">Нет сообщений.</Typography>}
|
||||
@@ -184,7 +189,7 @@ export function MessagesPage() {
|
||||
variant="contained"
|
||||
sx={{ minWidth: 140 }}
|
||||
onClick={() => msgMut.mutate()}
|
||||
disabled={msgMut.isPending || !text.trim()}
|
||||
disabled={msgMut.isPending || !canSendMessage}
|
||||
>
|
||||
Отправить
|
||||
</Button>
|
||||
|
||||
@@ -24,6 +24,7 @@ import { postProductReview, uploadReviewImage } from '@/entities/product/api/rev
|
||||
import { markOrderMessagesRead } from '@/entities/user/api/messages-api'
|
||||
import { formatPriceRub } from '@/shared/lib/format-price'
|
||||
import { orderStatusLabelRu } from '@/shared/lib/order-status-labels'
|
||||
import { RichTextMessageContent } from '@/shared/ui/RichTextMessageContent'
|
||||
import { RichTextMessageEditor } from '@/shared/ui/RichTextMessageEditor'
|
||||
|
||||
function reviewSubmitErrorMessage(err: unknown): string {
|
||||
@@ -95,6 +96,7 @@ export function OrderDetailPage() {
|
||||
})
|
||||
|
||||
const order = orderQuery.data?.item
|
||||
const canSendMessage = text.replace(/<[^>]*>/g, ' ').trim().length > 0
|
||||
|
||||
const eligibilityQuery = useQuery({
|
||||
queryKey: ['me', 'orders', id, 'review-eligibility'],
|
||||
@@ -322,12 +324,15 @@ export function OrderDetailPage() {
|
||||
bgcolor: m.authorType === 'admin' ? 'grey.100' : 'primary.50',
|
||||
border: 1,
|
||||
borderColor: 'divider',
|
||||
alignSelf: m.authorType === 'admin' ? 'flex-start' : 'flex-end',
|
||||
width: 'fit-content',
|
||||
maxWidth: '85%',
|
||||
}}
|
||||
>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{m.authorType === 'admin' ? 'Админ' : 'Вы'} · {new Date(m.createdAt).toLocaleString()}
|
||||
</Typography>
|
||||
<Typography sx={{ whiteSpace: 'pre-wrap' }}>{m.text}</Typography>
|
||||
<RichTextMessageContent value={m.text} />
|
||||
</Box>
|
||||
))}
|
||||
{order.messages.length === 0 && <Typography color="text.secondary">Пока сообщений нет.</Typography>}
|
||||
@@ -340,7 +345,7 @@ export function OrderDetailPage() {
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => msgMut.mutate()}
|
||||
disabled={msgMut.isPending || !text.trim()}
|
||||
disabled={msgMut.isPending || !canSendMessage}
|
||||
sx={{ minWidth: 160 }}
|
||||
>
|
||||
Отправить
|
||||
|
||||
Reference in New Issue
Block a user