feat: Pipeline↔Anfragen integration + Compare→Pipeline + KI stage detection

Navigation: Deal Pipeline moved after Vergleich (before Anfragen)

Compare → Pipeline:
- Bookmark icon per column header; BookmarkCheck when already in pipeline
- Passes propertyId, propertyAddress, area/rent labels on save

Pipeline cards now unit-level:
- propertyAddress shown with MapPin on every card
- Chat icon (MessageSquare) on cards with linked inquiry → navigates to /demand/anfragen?inquiry=xxx
- Detail panel: Chat chip links to specific inquiry thread, propertyAddress displayed

Anfragen → Pipeline KI detection:
- Keyword scan on every sent message (besichtigung → VISITED, mietvertrag → NEGOTIATION, unterschrieben → CLOSED_WON)
- Only advances stage, never goes back
- Purple KI alert banner with direct Pipeline link, auto-dismisses after 6s
- Pipeline badge in inquiry list + stage chip in chat header with nav link
- URL param ?inquiry=xxx pre-selects inquiry (used from Pipeline chat button)

Domain: PipelineItem gains propertyId, unitId, propertyAddress, inquiryId
Mock data: pl-001/pl-002/pl-004 linked to inq-001/inq-005/inq-004

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-22 21:42:21 +02:00
parent a002597f5b
commit 6a6ff7f2e2
8 changed files with 505 additions and 233 deletions
+14 -7
View File
@@ -33,13 +33,20 @@ export function UnifiedResultCard({ result, view = 'list' }: Props) {
label: 'Merken',
actionType: 'SAVE_SHORTLIST',
variant: 'secondary',
onClick: () => openSavedDialog({
resultId: result.matchId,
resultType: result.resultType,
title: getResultTitle(result),
matchScore: result.matchScore,
location: result.resultType !== 'FUTURE_AVAILABILITY' ? result.property.location?.city : undefined,
}),
onClick: () => {
const prop = result.resultType !== 'FUTURE_AVAILABILITY' ? (result as any).property : null
openSavedDialog({
resultId: result.matchId,
resultType: result.resultType,
title: getResultTitle(result),
matchScore: result.matchScore,
location: prop?.location?.city,
propertyId: prop?.id,
propertyAddress: prop ? `${prop.title}, ${prop.location?.city ?? ''}` : undefined,
areaLabel: prop?.areaSqm ? `${prop.areaSqm.toLocaleString('de-CH')}` : undefined,
rentLabel: prop?.rentPricePerSqm ? `CHF ${prop.rentPricePerSqm}/m²` : undefined,
})
},
},
{
id: 'compare',