fix: provide portfolio via BrokerAccountContext, fix Обзор link adding trailing dot

This commit is contained in:
Sergey Krylov 2026-06-23 20:41:23 +03:00
parent aea74bda3b
commit 76cffc061d
3 changed files with 65 additions and 49 deletions

View File

@ -1,3 +1,3 @@
export { useBrokerAccountContext } from './lib/useBrokerAccountContext' export { useBrokerAccountContext } from './lib/useBrokerAccountContext'
export type { BrokerAccountContext } from './ui/BrokerAccountLayout' export type { BrokerAccountContextValue } from './ui/BrokerAccountLayout'
export { BrokerAccountLayout } from './ui/BrokerAccountLayout' export { BrokerAccountLayout } from './ui/BrokerAccountLayout'

View File

@ -1,6 +1,10 @@
import { useParams } from '@tanstack/react-router' import { useContext } from 'react'
import { BrokerAccountContext } from '../ui/BrokerAccountLayout'
export function useBrokerAccountContext() { export function useBrokerAccountContext() {
const { accountId = '' } = useParams({ from: '/broker/$accountId' }) const context = useContext(BrokerAccountContext)
return { accountId } if (!context) {
throw new Error('useBrokerAccountContext must be used within BrokerAccountLayout')
}
return context
} }

View File

@ -1,8 +1,10 @@
import { Heading } from '@moex-vibe/design-system' import { Heading } from '@moex-vibe/design-system'
import { Box } from '@mui/material' import { Box } from '@mui/material'
import type { UseQueryResult } from '@tanstack/react-query'
import { Link, useParams } from '@tanstack/react-router' import { Link, useParams } from '@tanstack/react-router'
import type { ReactNode } from 'react' import { createContext, type ReactNode } from 'react'
import { useBrokerPortfolio } from '@/entities/broker-account' import { useBrokerPortfolio } from '@/entities/broker-account'
import type { BrokerPortfolio } from '@/shared/api'
const baseLinkStyle: React.CSSProperties = { const baseLinkStyle: React.CSSProperties = {
padding: '10px 12px', padding: '10px 12px',
@ -17,69 +19,79 @@ const baseLinkStyle: React.CSSProperties = {
} }
const links = [ const links = [
{ to: '.', label: 'Обзор' }, { to: '', label: 'Обзор' },
{ to: '/shares', label: 'Акции' }, { to: '/shares', label: 'Акции' },
{ to: '/bonds', label: 'Облигации' }, { to: '/bonds', label: 'Облигации' },
{ to: '/operations', label: 'Операции' }, { to: '/operations', label: 'Операции' },
{ to: '/events', label: 'События' }, { to: '/events', label: 'События' },
] ]
export interface BrokerAccountContextValue {
accountId: string
portfolio: UseQueryResult<BrokerPortfolio>
}
export const BrokerAccountContext = createContext<BrokerAccountContextValue | null>(null)
export function BrokerAccountLayout({ children }: { children: ReactNode }) { export function BrokerAccountLayout({ children }: { children: ReactNode }) {
const { accountId = '' } = useParams({ from: '/broker/$accountId' }) const { accountId = '' } = useParams({ from: '/broker/$accountId' })
const portfolio = useBrokerPortfolio(accountId) const portfolio = useBrokerPortfolio(accountId)
const basePath = `/broker/${encodeURIComponent(accountId)}` const basePath = `/broker/${encodeURIComponent(accountId)}`
return ( return (
<Box sx={{ display: 'grid', gap: 3 }}> <BrokerAccountContext.Provider value={{ accountId, portfolio }}>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.25 }}> <Box sx={{ display: 'grid', gap: 3 }}>
<Heading level={1}>{portfolio.data?.account.name || 'Брокерский счёт'}</Heading> <Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.25 }}>
</Box> <Heading level={1}>{portfolio.data?.account.name || 'Брокерский счёт'}</Heading>
</Box>
<Box
sx={{
display: 'grid',
gridTemplateColumns: '1fr',
gap: 2,
'@media (min-width: 720px)': {
gridTemplateColumns: 'minmax(150px, 190px) minmax(0, 1fr)',
gap: 3,
},
}}
>
<Box <Box
component="nav"
aria-label="Разделы брокерского счёта"
sx={{ sx={{
display: 'flex', display: 'grid',
flexDirection: 'column', gridTemplateColumns: '1fr',
gap: 0.5, gap: 2,
'@media (max-width: 719px)': { '@media (min-width: 720px)': {
flexDirection: 'row', gridTemplateColumns: 'minmax(150px, 190px) minmax(0, 1fr)',
overflowX: 'auto', gap: 3,
scrollbarWidth: 'thin',
}, },
}} }}
> >
{links.map((link) => ( <Box
<Link component="nav"
key={link.to} aria-label="Разделы брокерского счёта"
to={`${basePath}${link.to}`} sx={{
style={baseLinkStyle} display: 'flex',
activeProps={{ flexDirection: 'column',
style: { gap: 0.5,
...baseLinkStyle, '@media (max-width: 719px)': {
color: 'var(--color-primary)', flexDirection: 'row',
fontWeight: 700, overflowX: 'auto',
}, scrollbarWidth: 'thin',
}} },
> }}
{link.label} >
</Link> {links.map((link) => (
))} <Link
</Box> key={link.to}
to={`${basePath}${link.to}`}
style={baseLinkStyle}
activeOptions={{ exact: link.to === '' }}
activeProps={{
style: {
...baseLinkStyle,
color: 'var(--color-primary)',
fontWeight: 700,
},
}}
>
{link.label}
</Link>
))}
</Box>
<Box sx={{ minWidth: 0 }}>{children}</Box> <Box sx={{ minWidth: 0 }}>{children}</Box>
</Box>
</Box> </Box>
</Box> </BrokerAccountContext.Provider>
) )
} }