refactor: split AppShell, match-detail panels, extract useCompareData
AppShell.tsx: 627→116 lines - appShellConfig.ts: NavItem/WorkspaceConfig types, WORKSPACE_CONFIG, nav helpers - AppShellSidebar.tsx: Sidebar component with visual constants - AppShellTopBar.tsx: TopBar component Match-detail panels: - ScoreBreakdownPanel: 377→303 lines (scoreBreakdownConstants.ts + CriterionRow.tsx extracted) - LocationIntelligencePanel: 383→333 lines (SoftFactorBar.tsx extracted) - FutureAvailabilityContextPanel: 386→351 lines (futureAvailabilityConstants.tsx extracted) Compare.tsx: 485→441 lines - useCompareData hook: all queries and derived state extracted to hooks/useCompareData.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import { Box, Typography, Chip, Button, IconButton } from '@mui/material'
|
||||
import { Sparkles, Menu } from 'lucide-react'
|
||||
import { WorkspaceType } from '../../domain/enums'
|
||||
import { useAssistantStore } from '../../stores/assistantStore'
|
||||
import { OrganizationContextBadge } from './OrganizationContextBadge'
|
||||
import { NotificationButton } from './NotificationButton'
|
||||
import { UserMenu } from './UserMenu'
|
||||
import { WORKSPACE_CONFIG, getPageNameFromPath } from './appShellConfig'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface TopBarProps {
|
||||
activeWorkspace: WorkspaceType
|
||||
pathname: string
|
||||
onMenuClick?: () => void
|
||||
isMobile?: boolean
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Component
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function TopBar({ activeWorkspace, pathname, onMenuClick, isMobile }: TopBarProps) {
|
||||
const config = WORKSPACE_CONFIG[activeWorkspace]
|
||||
const pageName = getPageNameFromPath(pathname)
|
||||
const openAssistant = useAssistantStore(s => s.open)
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="header"
|
||||
sx={{
|
||||
height: 56,
|
||||
flexShrink: 0,
|
||||
backgroundColor: '#ffffff',
|
||||
borderBottom: '1px solid #e2e8f0',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
px: { xs: 1.5, sm: 3 },
|
||||
}}
|
||||
>
|
||||
{/* Left side */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
{isMobile && (
|
||||
<IconButton size="small" onClick={onMenuClick} sx={{ mr: 0.5 }}>
|
||||
<Menu size={20} />
|
||||
</IconButton>
|
||||
)}
|
||||
<Chip
|
||||
label={config.label}
|
||||
size="small"
|
||||
sx={{
|
||||
backgroundColor: config.chipColor,
|
||||
color: '#ffffff',
|
||||
fontWeight: 600,
|
||||
fontSize: '0.7rem',
|
||||
height: 22,
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
variant="body1"
|
||||
sx={{ fontWeight: 500, color: '#1e293b', fontSize: { xs: '0.85rem', sm: '0.9375rem' } }}
|
||||
>
|
||||
{pageName}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Right side */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: { xs: 0.5, sm: 1 } }}>
|
||||
<Box sx={{ display: { xs: 'none', sm: 'flex' } }}>
|
||||
<OrganizationContextBadge />
|
||||
</Box>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
startIcon={<Sparkles size={14} />}
|
||||
onClick={openAssistant}
|
||||
sx={{ textTransform: 'none', fontSize: '0.8125rem', display: { xs: 'none', md: 'flex' } }}
|
||||
>
|
||||
AI Assistent
|
||||
</Button>
|
||||
<IconButton size="small" onClick={openAssistant} sx={{ display: { xs: 'flex', md: 'none' } }}>
|
||||
<Sparkles size={18} />
|
||||
</IconButton>
|
||||
<NotificationButton />
|
||||
<UserMenu />
|
||||
</Box>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user