fix: Compare→Pipeline flow, pipeline card navigation, remove floating AI button
- Remove CompareTray fixed bottom bar; replace with compare count badge on Vergleich nav item - Pipeline cards redesigned to match search result card visual style (MatchScoreDisplay, type chip, stage chip, MapPin layout) - CompareColumnHeader: redesigned with proper Details/Merken action buttons, clickable title - AddToPipelineDialog now mounted on Compare page (was missing — bookmark had no effect) - Pipeline card ExternalLink icon navigates to property detail page; detailPath prefers stable propertyId over volatile session matchId - Add matchId field to PipelineItem domain; pipelineStore stores it on save - All 8 mock pipeline items now have propertyId for reliable cross-session navigation - Remove GlobalAIAssistantButton floating overlay (was blocking form submissions and clicks) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { Box, Chip, IconButton, Tooltip, Typography } from '@mui/material'
|
||||
import { X, AlertTriangle, Bookmark, BookmarkCheck } from 'lucide-react'
|
||||
import { Box, Button, Chip, IconButton, Tooltip, Typography } from '@mui/material'
|
||||
import { X, AlertTriangle, BookmarkCheck, ExternalLink, Kanban } from 'lucide-react'
|
||||
import { useNavigate } from 'react-router'
|
||||
import { usePipelineStore } from '../../stores/pipelineStore'
|
||||
import type { UnifiedMatchResult } from '../../domain/unifiedResult'
|
||||
|
||||
@@ -18,6 +19,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export function CompareColumnHeader({ item, onRemove }: Props) {
|
||||
const navigate = useNavigate()
|
||||
const { items: pipelineItems, openSavedDialog } = usePipelineStore()
|
||||
|
||||
const meta = TYPE_META[item.resultType] ?? { label: item.resultType, color: '#64748b' }
|
||||
@@ -53,45 +55,43 @@ export function CompareColumnHeader({ item, onRemove }: Props) {
|
||||
|
||||
return (
|
||||
<Box sx={{ p: 0.5 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', mb: 1 }}>
|
||||
|
||||
{/* Row 1: type chip + remove */}
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
|
||||
<Chip label={meta.label} size="small" sx={{ bgcolor: meta.color, color: 'white', fontWeight: 600, fontSize: 10 }} />
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.25 }}>
|
||||
<Tooltip title={isInPipeline ? 'Bereits in Pipeline' : 'In Pipeline merken'}>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={handleSave}
|
||||
sx={{
|
||||
p: 0.25,
|
||||
color: isInPipeline ? '#1a7a4a' : '#94a3b8',
|
||||
'&:hover': { color: isInPipeline ? '#1a7a4a' : '#1e3a5f' },
|
||||
}}
|
||||
>
|
||||
{isInPipeline
|
||||
? <BookmarkCheck size={14} />
|
||||
: <Bookmark size={14} />}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<IconButton size="small" onClick={onRemove} sx={{ p: 0.25, ml: 0.25 }}>
|
||||
<X size={14} />
|
||||
<Tooltip title="Aus Vergleich entfernen">
|
||||
<IconButton size="small" onClick={onRemove} sx={{ p: 0.375, color: '#94a3b8', '&:hover': { color: '#c0392b' } }}>
|
||||
<X size={15} />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
<Typography variant="subtitle2" sx={{ fontWeight: 700, mb: 0.25, lineHeight: 1.3 }}>
|
||||
{/* Row 2: title (clickable) */}
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
sx={{
|
||||
fontWeight: 700, lineHeight: 1.3, mb: 0.25,
|
||||
cursor: 'pointer',
|
||||
'&:hover': { color: '#1e3a5f' },
|
||||
}}
|
||||
onClick={() => navigate(`/demand/results/${item.matchId}`)}
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mb: 1 }}>
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mb: 1.25 }}>
|
||||
{subtitle}{district ? `, ${district}` : ''}
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ display: 'flex', alignItems: 'baseline', gap: 0.5, mb: 0.5 }}>
|
||||
{/* Row 3: score */}
|
||||
<Box sx={{ display: 'flex', alignItems: 'baseline', gap: 0.5, mb: 1 }}>
|
||||
<Typography variant="h4" sx={{ fontWeight: 800, color: SCORE_COLOR(item.matchScore), lineHeight: 1 }}>
|
||||
{item.matchScore}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary">/100</Typography>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5, mt: 0.5 }}>
|
||||
{/* Row 4: meta chips */}
|
||||
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5, mb: 1.25 }}>
|
||||
<Tooltip title="Konfidenz">
|
||||
<Chip
|
||||
label={`${confidence}% Konfidenz`}
|
||||
@@ -113,7 +113,7 @@ export function CompareColumnHeader({ item, onRemove }: Props) {
|
||||
</Box>
|
||||
|
||||
{item.resultType === 'FUTURE_AVAILABILITY' && sig && (
|
||||
<Box sx={{ mt: 1, p: 0.75, bgcolor: '#faf5ff', borderRadius: 1, border: '1px solid #e9d5ff' }}>
|
||||
<Box sx={{ mb: 1.25, p: 0.75, bgcolor: '#faf5ff', borderRadius: 1, border: '1px solid #e9d5ff' }}>
|
||||
<Typography variant="caption" sx={{ color: '#7c3aed', fontWeight: 600, display: 'block' }}>
|
||||
Probabilistisches Signal
|
||||
</Typography>
|
||||
@@ -122,6 +122,41 @@ export function CompareColumnHeader({ item, onRemove }: Props) {
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Row 5: action buttons */}
|
||||
<Box sx={{ display: 'flex', gap: 0.75, pt: 1, borderTop: '1px solid #f1f5f9' }}>
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
startIcon={<ExternalLink size={12} />}
|
||||
onClick={() => navigate(`/demand/results/${item.matchId}`)}
|
||||
sx={{ flex: 1, textTransform: 'none', fontSize: '0.72rem', py: 0.5 }}
|
||||
>
|
||||
Details
|
||||
</Button>
|
||||
{isInPipeline ? (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
startIcon={<BookmarkCheck size={12} />}
|
||||
disabled
|
||||
sx={{ flex: 1, textTransform: 'none', fontSize: '0.72rem', py: 0.5, color: '#1a7a4a', borderColor: '#86efac' }}
|
||||
>
|
||||
In Pipeline
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
size="small"
|
||||
variant="contained"
|
||||
startIcon={<Kanban size={12} />}
|
||||
onClick={handleSave}
|
||||
sx={{ flex: 1, textTransform: 'none', fontSize: '0.72rem', py: 0.5, bgcolor: '#1e3a5f', '&:hover': { bgcolor: '#162d4a' } }}
|
||||
>
|
||||
Merken
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user