Merge branch 'refactor'
This commit is contained in:
@@ -1,21 +1,15 @@
|
||||
import { useState } from 'react'
|
||||
import AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined'
|
||||
import DarkModeOutlinedIcon from '@mui/icons-material/DarkModeOutlined'
|
||||
import LightModeOutlinedIcon from '@mui/icons-material/LightModeOutlined'
|
||||
import LocalShippingOutlinedIcon from '@mui/icons-material/LocalShippingOutlined'
|
||||
import MenuOutlinedIcon from '@mui/icons-material/MenuOutlined'
|
||||
import ShoppingCartOutlinedIcon from '@mui/icons-material/ShoppingCartOutlined'
|
||||
import AppBar from '@mui/material/AppBar'
|
||||
import Badge from '@mui/material/Badge'
|
||||
import Box from '@mui/material/Box'
|
||||
import Button from '@mui/material/Button'
|
||||
import Divider from '@mui/material/Divider'
|
||||
import Drawer from '@mui/material/Drawer'
|
||||
import FormControl from '@mui/material/FormControl'
|
||||
import IconButton from '@mui/material/IconButton'
|
||||
import InputLabel from '@mui/material/InputLabel'
|
||||
import ListItemText from '@mui/material/ListItemText'
|
||||
import Menu from '@mui/material/Menu'
|
||||
import MenuItem from '@mui/material/MenuItem'
|
||||
import Select from '@mui/material/Select'
|
||||
import type { SelectChangeEvent } from '@mui/material/Select'
|
||||
@@ -31,9 +25,12 @@ import type { ColorScheme } from '@/app/providers/theme-controller'
|
||||
import { useThemeController } from '@/app/providers/theme-controller'
|
||||
import { fetchMyCart } from '@/entities/cart/api/cart-api'
|
||||
import { fetchMyOrders } from '@/entities/order/api/order-api'
|
||||
import { CartBadge } from '@/features/cart/cart-badge'
|
||||
import { UserMenu } from '@/features/user/user-menu'
|
||||
import { STORE_NAME } from '@/shared/config'
|
||||
import { $user, logout, tokenSet } from '@/shared/model/auth'
|
||||
import { BearLogo } from '@/shared/ui/BearLogo'
|
||||
import { NavigationDrawer } from '@/widgets/navigation-drawer'
|
||||
|
||||
type NavItem = { label: string; to: string }
|
||||
|
||||
@@ -175,7 +172,6 @@ export function AppHeader() {
|
||||
queryFn: fetchMyCart,
|
||||
enabled: Boolean(user) && !isAdmin,
|
||||
})
|
||||
|
||||
const cartCount = cartQuery.data?.items?.length ?? 0
|
||||
|
||||
const ordersQuery = useQuery({
|
||||
@@ -183,53 +179,46 @@ export function AppHeader() {
|
||||
queryFn: fetchMyOrders,
|
||||
enabled: Boolean(user) && !isAdmin,
|
||||
})
|
||||
|
||||
const activeOrdersCount = (ordersQuery.data?.items ?? []).filter(
|
||||
(o) => o.status !== 'DONE' && o.status !== 'CANCELLED',
|
||||
).length
|
||||
|
||||
const [userAnchorEl, setUserAnchorEl] = useState<null | HTMLElement>(null)
|
||||
const userMenuOpen = Boolean(userAnchorEl)
|
||||
|
||||
const [mobileOpen, setMobileOpen] = useState(false)
|
||||
const theme = useTheme()
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
|
||||
|
||||
const onSchemeChange = (e: SelectChangeEvent<string>) => {
|
||||
setScheme(e.target.value as ColorScheme)
|
||||
}
|
||||
|
||||
const onSchemeChange = (e: SelectChangeEvent<string>) => setScheme(e.target.value as ColorScheme)
|
||||
const onModeChange = (e: SelectChangeEvent<string>) => {
|
||||
const v = e.target.value
|
||||
if (v === 'system' || v === 'light' || v === 'dark') setMode(v)
|
||||
}
|
||||
|
||||
const openUserMenu = (e: React.MouseEvent<HTMLElement>) => setUserAnchorEl(e.currentTarget)
|
||||
const closeUserMenu = () => setUserAnchorEl(null)
|
||||
|
||||
const openMobile = () => setMobileOpen(true)
|
||||
const closeMobile = () => setMobileOpen(false)
|
||||
|
||||
const go = (to: string) => {
|
||||
closeMobile()
|
||||
closeUserMenu()
|
||||
setMobileOpen(false)
|
||||
navigate(to)
|
||||
}
|
||||
|
||||
const onLogout = () => {
|
||||
tokenSet(null)
|
||||
logout()
|
||||
closeMobile()
|
||||
closeUserMenu()
|
||||
setMobileOpen(false)
|
||||
navigate('/')
|
||||
}
|
||||
|
||||
const themeControls = { scheme, mode, resolvedMode, onSchemeChange, onModeChange, onCycleMode: cycleMode }
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppBar position="sticky" color="primary" elevation={0} sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<Toolbar>
|
||||
{isMobile && (
|
||||
<IconButton color="inherit" onClick={openMobile} aria-label="Открыть меню" edge="start" sx={{ mr: 1 }}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
onClick={() => setMobileOpen(true)}
|
||||
aria-label="Открыть меню"
|
||||
edge="start"
|
||||
sx={{ mr: 1 }}
|
||||
>
|
||||
<MenuOutlinedIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
@@ -272,58 +261,11 @@ export function AppHeader() {
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Tooltip title={user ? 'Корзина' : 'Авторизуйтесь для совершения покупок'}>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
sx={{ ml: 1 }}
|
||||
onClick={() => {
|
||||
if (!user) navigate('/auth')
|
||||
else navigate('/cart')
|
||||
}}
|
||||
aria-label="Корзина"
|
||||
>
|
||||
<Badge color="secondary" badgeContent={user ? cartCount : 0} invisible={!user || cartCount === 0}>
|
||||
<ShoppingCartOutlinedIcon />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<CartBadge user={user} cartCount={cartCount} onNavigate={navigate} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{!isAdmin && (
|
||||
<>
|
||||
<IconButton color="inherit" onClick={openUserMenu} sx={{ ml: 1 }} aria-label="Пользователь">
|
||||
<Badge
|
||||
variant="dot"
|
||||
color="success"
|
||||
overlap="circular"
|
||||
invisible={!user}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||
>
|
||||
<AccountCircleOutlinedIcon />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
|
||||
<Menu
|
||||
anchorEl={userAnchorEl}
|
||||
open={userMenuOpen}
|
||||
onClose={closeUserMenu}
|
||||
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
|
||||
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
|
||||
>
|
||||
{user ? (
|
||||
<>
|
||||
<MenuItem onClick={() => go('/me')}>
|
||||
<ListItemText primary={(user.name && user.name.trim()) || user.email} secondary="Профиль" />
|
||||
</MenuItem>
|
||||
<MenuItem onClick={onLogout}>Выход</MenuItem>
|
||||
</>
|
||||
) : (
|
||||
<MenuItem onClick={() => go('/auth')}>Войти / регистрация</MenuItem>
|
||||
)}
|
||||
</Menu>
|
||||
</>
|
||||
)}
|
||||
{!isAdmin && <UserMenu user={user} onNavigate={navigate} onLogout={onLogout} />}
|
||||
|
||||
{isAdmin && user && !isMobile && (
|
||||
<Button color="inherit" onClick={onLogout} sx={{ ml: 1 }}>
|
||||
@@ -331,76 +273,21 @@ export function AppHeader() {
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{!isMobile && (
|
||||
<ThemeControlsDesktop
|
||||
scheme={scheme}
|
||||
mode={mode}
|
||||
resolvedMode={resolvedMode}
|
||||
onSchemeChange={onSchemeChange}
|
||||
onModeChange={onModeChange}
|
||||
onCycleMode={cycleMode}
|
||||
/>
|
||||
)}
|
||||
{!isMobile && <ThemeControlsDesktop {...themeControls} />}
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
||||
<Drawer
|
||||
<NavigationDrawer
|
||||
open={mobileOpen}
|
||||
onClose={closeMobile}
|
||||
slotProps={{ paper: { sx: { width: 320, maxWidth: '85vw' } } }}
|
||||
ModalProps={{ keepMounted: true }}
|
||||
>
|
||||
<Box sx={{ p: 2 }}>
|
||||
<Box sx={{ mb: 2, display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<BearLogo sx={{ fontSize: 28 }} />
|
||||
<Typography variant="h6">{STORE_NAME}</Typography>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
{headerNavItems.map((i) => (
|
||||
<Button key={i.to} variant="text" onClick={() => go(i.to)} sx={{ justifyContent: 'flex-start' }}>
|
||||
{i.label}
|
||||
</Button>
|
||||
))}
|
||||
{!isAdmin && (
|
||||
<Button variant="text" onClick={() => go(user ? '/cart' : '/auth')} sx={{ justifyContent: 'flex-start' }}>
|
||||
Корзина
|
||||
</Button>
|
||||
)}
|
||||
{user && !isAdmin && (
|
||||
<Button variant="text" onClick={() => go('/me/orders')} sx={{ justifyContent: 'flex-start' }}>
|
||||
Заказы
|
||||
</Button>
|
||||
)}
|
||||
{!isAdmin && (
|
||||
<Button variant="text" onClick={() => go(user ? '/me' : '/auth')} sx={{ justifyContent: 'flex-start' }}>
|
||||
{user ? 'Профиль' : 'Вход / регистрация'}
|
||||
</Button>
|
||||
)}
|
||||
{!user && isAdmin && (
|
||||
<Button variant="text" onClick={() => go('/auth')} sx={{ justifyContent: 'flex-start' }}>
|
||||
Вход / регистрация
|
||||
</Button>
|
||||
)}
|
||||
{user && (
|
||||
<Button variant="text" color="error" onClick={onLogout} sx={{ justifyContent: 'flex-start' }}>
|
||||
Выход
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ my: 2 }} />
|
||||
|
||||
<ThemeControlsMobile
|
||||
scheme={scheme}
|
||||
mode={mode}
|
||||
resolvedMode={resolvedMode}
|
||||
onSchemeChange={onSchemeChange}
|
||||
onModeChange={onModeChange}
|
||||
onCycleMode={cycleMode}
|
||||
/>
|
||||
</Box>
|
||||
</Drawer>
|
||||
onClose={() => setMobileOpen(false)}
|
||||
user={user}
|
||||
isAdmin={isAdmin}
|
||||
navItems={headerNavItems}
|
||||
themeControls={themeControls}
|
||||
onNavigate={go}
|
||||
onLogout={onLogout}
|
||||
ThemeControlsMobile={ThemeControlsMobile}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user