feat: in-memory inquiry flow — send from card, pipeline, and detail
New inquiryStore (Zustand) holds sent inquiries for the session. InquiryQuickDialog reads from the store (no props), renders wherever needed. Sent inquiries appear immediately at the top of the Anfragen page. Entry points: - Match cards: "Anfrage" button on every card in the results feed - MatchDetail: primary action in NextActionsPanel - Pipeline: chat icon on every DraggableCard Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,23 +1,17 @@
|
||||
import { Box, Button, Paper, Typography } from '@mui/material'
|
||||
import { MessageSquare } from 'lucide-react'
|
||||
import type { Match, NextBestAction } from '../../domain/match'
|
||||
|
||||
const PRIORITY_ORDER: Record<string, number> = { HIGH: 0, MEDIUM: 1, LOW: 2 }
|
||||
|
||||
const PRIORITY_COLOR: Record<string, 'contained' | 'outlined'> = {
|
||||
HIGH: 'contained',
|
||||
MEDIUM: 'outlined',
|
||||
LOW: 'outlined',
|
||||
}
|
||||
|
||||
interface Props {
|
||||
match: Match
|
||||
onCompare?: () => void
|
||||
onShortlist?: () => void
|
||||
onReject?: () => void
|
||||
onReview?: () => void
|
||||
onPipeline?: () => void
|
||||
onInquire?: () => void
|
||||
}
|
||||
|
||||
export function NextActionsPanel({ match, onCompare, onShortlist, onReject, onReview }: Props) {
|
||||
export function NextActionsPanel({ match, onCompare, onPipeline, onInquire }: Props) {
|
||||
const engineActions: NextBestAction[] = [...(match.nextBestActions ?? [])].sort(
|
||||
(a, b) => (PRIORITY_ORDER[a.priority] ?? 2) - (PRIORITY_ORDER[b.priority] ?? 2)
|
||||
)
|
||||
@@ -26,37 +20,41 @@ export function NextActionsPanel({ match, onCompare, onShortlist, onReject, onRe
|
||||
<Paper sx={{ p: 2.5, mb: 2 }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 700, mb: 1.5 }}>Empfohlene Aktionen</Typography>
|
||||
|
||||
{engineActions.length > 0 && (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.75, mb: 1.5 }}>
|
||||
{engineActions.map((action, i) => (
|
||||
<Box key={i}>
|
||||
<Button
|
||||
fullWidth
|
||||
size="small"
|
||||
variant={PRIORITY_COLOR[action.priority]}
|
||||
sx={
|
||||
action.priority === 'HIGH'
|
||||
? { bgcolor: '#1e3a5f', '&:hover': { bgcolor: '#162d4a' }, justifyContent: 'flex-start' }
|
||||
: { justifyContent: 'flex-start' }
|
||||
}
|
||||
>
|
||||
{action.label}
|
||||
</Button>
|
||||
{action.description && (
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 0.25, px: 1 }}>
|
||||
{action.description}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Standard actions */}
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.75 }}>
|
||||
{onShortlist && (
|
||||
<Button fullWidth size="small" variant="outlined" onClick={onShortlist} sx={{ justifyContent: 'flex-start' }}>
|
||||
Zur Shortlist hinzufügen
|
||||
{onInquire && (
|
||||
<Button
|
||||
fullWidth
|
||||
size="small"
|
||||
variant="contained"
|
||||
startIcon={<MessageSquare size={14} />}
|
||||
onClick={onInquire}
|
||||
sx={{ justifyContent: 'flex-start', bgcolor: '#1e3a5f', '&:hover': { bgcolor: '#162d4a' } }}
|
||||
>
|
||||
Anfrage senden
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{engineActions.length > 0 && engineActions.map((action, i) => (
|
||||
<Box key={i}>
|
||||
<Button
|
||||
fullWidth
|
||||
size="small"
|
||||
variant="outlined"
|
||||
sx={{ justifyContent: 'flex-start' }}
|
||||
>
|
||||
{action.label}
|
||||
</Button>
|
||||
{action.description && (
|
||||
<Typography variant="caption" color="text.secondary" sx={{ display: 'block', mt: 0.25, px: 1 }}>
|
||||
{action.description}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
{onPipeline && (
|
||||
<Button fullWidth size="small" variant="outlined" onClick={onPipeline} sx={{ justifyContent: 'flex-start' }}>
|
||||
Zur Pipeline hinzufügen
|
||||
</Button>
|
||||
)}
|
||||
{onCompare && (
|
||||
@@ -64,16 +62,6 @@ export function NextActionsPanel({ match, onCompare, onShortlist, onReject, onRe
|
||||
Zum Vergleich hinzufügen
|
||||
</Button>
|
||||
)}
|
||||
{onReview && (
|
||||
<Button fullWidth size="small" variant="outlined" onClick={onReview} sx={{ justifyContent: 'flex-start', color: '#d97706', borderColor: '#d97706' }}>
|
||||
Zur Überprüfung senden
|
||||
</Button>
|
||||
)}
|
||||
{onReject && (
|
||||
<Button fullWidth size="small" variant="outlined" onClick={onReject} sx={{ justifyContent: 'flex-start', color: '#c0392b', borderColor: '#c0392b' }}>
|
||||
Match ablehnen
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</Paper>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user