test refactor

This commit is contained in:
@kirill.komarov
2026-05-14 19:54:45 +05:00
parent 8165f75a78
commit ce9883f8c9
12 changed files with 175 additions and 175 deletions
+42 -152
View File
@@ -1,19 +1,12 @@
import { useState } from 'react'
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 { useEffect, useState } from 'react'
import Inventory2OutlinedIcon from '@mui/icons-material/Inventory2Outlined'
import MenuRoundedIcon from '@mui/icons-material/MenuRounded'
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 FormControl from '@mui/material/FormControl'
import IconButton from '@mui/material/IconButton'
import InputLabel from '@mui/material/InputLabel'
import MenuItem from '@mui/material/MenuItem'
import Select from '@mui/material/Select'
import type { SelectChangeEvent } from '@mui/material/Select'
import { useTheme } from '@mui/material/styles'
import { alpha, useTheme } from '@mui/material/styles'
import Toolbar from '@mui/material/Toolbar'
import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography'
@@ -21,7 +14,6 @@ import useMediaQuery from '@mui/material/useMediaQuery'
import { useQuery } from '@tanstack/react-query'
import { useUnit } from 'effector-react'
import { Link as RouterLink, useNavigate } from 'react-router-dom'
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'
@@ -29,143 +21,24 @@ 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 type { ColorScheme } from '@/shared/model/theme'
import { BearLogo } from '@/shared/ui/BearLogo'
import { ModeSwitcher } from '@/shared/ui/ModeSwitcher'
import { SchemeSwitcher } from '@/shared/ui/SchemeSwitcher'
import { NavigationDrawer } from '@/widgets/navigation-drawer'
type NavItem = { label: string; to: string }
const navItems: NavItem[] = [{ label: 'Каталог', to: '/' }]
function ThemeControlsDesktop(props: {
scheme: string
mode: string
resolvedMode: 'light' | 'dark'
onSchemeChange: (e: SelectChangeEvent<string>) => void
onModeChange: (e: SelectChangeEvent<string>) => void
onCycleMode: () => void
}) {
const { scheme, mode, resolvedMode, onSchemeChange, onModeChange, onCycleMode } = props
return (
<>
<FormControl
size="small"
sx={{
ml: 2,
minWidth: 160,
'& .MuiInputLabel-root': { color: 'rgba(255,255,255,0.85)' },
'& .MuiInputLabel-root.Mui-focused': { color: '#fff' },
'& .MuiInputLabel-root.MuiInputLabel-shrink': { color: 'rgba(255,255,255,0.92)' },
}}
>
<InputLabel id="scheme-label">Схема</InputLabel>
<Select
labelId="scheme-label"
value={scheme}
label="Схема"
onChange={onSchemeChange}
sx={{
color: 'inherit',
'.MuiOutlinedInput-notchedOutline': { borderColor: 'rgba(255,255,255,0.5)' },
'&:hover .MuiOutlinedInput-notchedOutline': { borderColor: 'rgba(255,255,255,0.9)' },
'&.Mui-focused .MuiOutlinedInput-notchedOutline': { borderColor: 'rgba(255,255,255,0.95)' },
'.MuiSvgIcon-root': { color: 'inherit' },
}}
>
<MenuItem value="craft">Крафт</MenuItem>
<MenuItem value="forest">Лес</MenuItem>
<MenuItem value="ocean">Океан</MenuItem>
<MenuItem value="berry">Ягоды</MenuItem>
</Select>
</FormControl>
<FormControl
size="small"
sx={{
ml: 2,
minWidth: 150,
'& .MuiInputLabel-root': { color: 'rgba(255,255,255,0.85)' },
'& .MuiInputLabel-root.Mui-focused': { color: '#fff' },
'& .MuiInputLabel-root.MuiInputLabel-shrink': { color: 'rgba(255,255,255,0.92)' },
}}
>
<InputLabel id="mode-label">Тема</InputLabel>
<Select
labelId="mode-label"
value={mode}
label="Тема"
onChange={onModeChange}
sx={{
color: 'inherit',
'.MuiOutlinedInput-notchedOutline': { borderColor: 'rgba(255,255,255,0.5)' },
'&:hover .MuiOutlinedInput-notchedOutline': { borderColor: 'rgba(255,255,255,0.9)' },
'&.Mui-focused .MuiOutlinedInput-notchedOutline': { borderColor: 'rgba(255,255,255,0.95)' },
'.MuiSvgIcon-root': { color: 'inherit' },
}}
>
<MenuItem value="system">Авто (система)</MenuItem>
<MenuItem value="light">Светлая</MenuItem>
<MenuItem value="dark">Тёмная</MenuItem>
</Select>
</FormControl>
<IconButton
color="inherit"
onClick={onCycleMode}
sx={{ ml: 1 }}
aria-label="Переключить режим темы (авто/светлая/тёмная)"
title={`Сейчас: ${mode === 'system' ? `авто (${resolvedMode})` : mode}`}
>
{resolvedMode === 'dark' ? <LightModeOutlinedIcon /> : <DarkModeOutlinedIcon />}
</IconButton>
</>
)
}
function ThemeControlsMobile(props: {
scheme: string
mode: string
resolvedMode: 'light' | 'dark'
onSchemeChange: (e: SelectChangeEvent<string>) => void
onModeChange: (e: SelectChangeEvent<string>) => void
onCycleMode: () => void
}) {
const { scheme, mode, resolvedMode, onSchemeChange, onModeChange, onCycleMode } = props
return (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<FormControl size="small" fullWidth>
<InputLabel id="scheme-label-mobile">Схема</InputLabel>
<Select labelId="scheme-label-mobile" value={scheme} label="Схема" onChange={onSchemeChange}>
<MenuItem value="craft">Крафт</MenuItem>
<MenuItem value="forest">Лес</MenuItem>
<MenuItem value="ocean">Океан</MenuItem>
<MenuItem value="berry">Ягоды</MenuItem>
</Select>
</FormControl>
<FormControl size="small" fullWidth>
<InputLabel id="mode-label-mobile">Тема</InputLabel>
<Select labelId="mode-label-mobile" value={mode} label="Тема" onChange={onModeChange}>
<MenuItem value="system">Авто (система)</MenuItem>
<MenuItem value="light">Светлая</MenuItem>
<MenuItem value="dark">Тёмная</MenuItem>
</Select>
</FormControl>
<Button variant="outlined" onClick={onCycleMode}>
Быстро переключить: {mode === 'system' ? `авто (${resolvedMode})` : mode}
</Button>
</Box>
)
}
export function AppHeader() {
const { mode, resolvedMode, scheme, setMode, setScheme, cycleMode } = useThemeController()
const { mode, resolvedMode, scheme, setScheme, cycleMode } = useThemeController()
const user = useUnit($user)
const navigate = useNavigate()
const isAdmin = Boolean(user?.isAdmin)
const headerNavItems = isAdmin ? [...navItems, { label: 'Админка', to: '/admin' }] : navItems
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
const cartQuery = useQuery({
queryKey: ['me', 'cart'],
@@ -184,14 +57,14 @@ export function AppHeader() {
).length
const [mobileOpen, setMobileOpen] = useState(false)
const theme = useTheme()
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
const [scrolled, setScrolled] = useState(false)
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)
}
useEffect(() => {
const handler = () => setScrolled(window.scrollY > 0)
handler()
window.addEventListener('scroll', handler, { passive: true })
return () => window.removeEventListener('scroll', handler)
}, [])
const go = (to: string) => {
setMobileOpen(false)
@@ -205,11 +78,20 @@ export function AppHeader() {
navigate('/')
}
const themeControls = { scheme, mode, resolvedMode, onSchemeChange, onModeChange, onCycleMode: cycleMode }
return (
<>
<AppBar position="sticky" color="primary" elevation={0} sx={{ borderBottom: 1, borderColor: 'divider' }}>
<AppBar
position="sticky"
color="primary"
elevation={scrolled ? 2 : 0}
sx={{
borderBottom: 1,
borderColor: 'divider',
bgcolor: alpha(theme.palette.primary.main, 0.88),
backdropFilter: 'blur(8px)',
transition: 'box-shadow 0.2s ease, background-color 0.2s ease',
}}
>
<Toolbar>
{isMobile && (
<IconButton
@@ -219,7 +101,7 @@ export function AppHeader() {
edge="start"
sx={{ mr: 1 }}
>
<MenuOutlinedIcon />
<MenuRoundedIcon />
</IconButton>
)}
@@ -255,7 +137,7 @@ export function AppHeader() {
<Tooltip title="Заказы">
<IconButton color="inherit" sx={{ ml: 1 }} onClick={() => navigate('/me/orders')} aria-label="Заказы">
<Badge color="secondary" badgeContent={activeOrdersCount} invisible={activeOrdersCount === 0}>
<LocalShippingOutlinedIcon />
<Inventory2OutlinedIcon />
</Badge>
</IconButton>
</Tooltip>
@@ -273,7 +155,12 @@ export function AppHeader() {
</Button>
)}
{!isMobile && <ThemeControlsDesktop {...themeControls} />}
{!isMobile && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, ml: 1.5 }}>
<SchemeSwitcher value={scheme} onChange={(s: ColorScheme) => setScheme(s)} />
<ModeSwitcher mode={mode} resolvedMode={resolvedMode} onCycleMode={cycleMode} />
</Box>
)}
</Toolbar>
</AppBar>
@@ -283,10 +170,13 @@ export function AppHeader() {
user={user}
isAdmin={isAdmin}
navItems={headerNavItems}
themeControls={themeControls}
scheme={scheme}
mode={mode}
resolvedMode={resolvedMode}
onSchemeChange={(s: ColorScheme) => setScheme(s)}
onCycleMode={cycleMode}
onNavigate={go}
onLogout={onLogout}
ThemeControlsMobile={ThemeControlsMobile}
/>
</>
)
@@ -1,9 +1,6 @@
import { createContext, type PropsWithChildren, useContext, useEffect, useMemo, useState } from 'react'
import type { PaletteMode } from '@mui/material'
export type ColorScheme = 'craft' | 'forest' | 'ocean' | 'berry'
export type ThemeModePreference = 'system' | PaletteMode
import type { ColorScheme, ThemeModePreference } from '@/shared/model/theme'
export type ThemeSettings = {
mode: ThemeModePreference