feat(livia)!: Exposé-Funktion vollständig entfernt
Runde 8 hat Livia zur Research- & Market-Intelligence-Agentin gemacht. Die Exposé-Erstellung war der Kern ihrer alten Rolle und fällt mit ihr weg — sie wird nicht nachgeordnet weitergeführt. Ein zweiter Reiter hätte die Funktion sichtbar gelassen und die neue Positionierung damit halbiert. Entfernt: 23 Dateien (Arbeitsbereich, dreistufiger Assistent, Dossier mit elf Bereichen, Provider, Services, Hooks, Feldkatalog, Mockdaten, deterministischer Textbaustein) sowie `generateExposeText` aus `IAIService` und beiden Implementierungen. Livias Arbeitsplatz zeigt jetzt nur noch die Recherche-Leads — ohne Reiterbalken, weil eine Leiste mit einem Eintrag eine Alternative behauptet, die es nicht gibt. Ihr Personalblatt, die Bearbeitungsverlaufs-Einträge und die Teamdokumentation sind auf die neue Rolle nachgezogen; die beiden Beispielvorgänge zeigen jetzt eine Leaderzeugung und ein Review mit widersprüchlichen Quellen statt Lagebeschrieb und Exposétext. Bei Nora entfällt die Mehrfachauswahl in der Objektliste: sie diente allein der Weiterleitung an die Exposé-Erstellung. Eine Auswahl ohne Ziel wäre ein Bedienelement, das nichts auslöst. Die Matching-Darstellung selbst bleibt unverändert. Der Wiederaufbau ist in `archive/livia/` beschrieben; das Manifest hält jetzt fest, welche seiner Annahmen eingetreten sind und welche nicht — Livia bleibt im Team, nur die Funktion ist weg. Geprüft: tsc 0 Fehler, eslint 0 Fehler/0 Warnungen, 423/423 Tests grün, Produktionsbuild erfolgreich, Smoke-Test über sieben Seiten ohne Laufzeitfehler, 12/12 Abnahmekriterien erfüllt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
f5451f649f
commit
a219d3f2ec
33 files changed
+178
-2474
No files matched your search
@@ -1,9 +1,7 @@
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { Alert, Box, Button, Chip, Divider, Typography } from '@mui/material'
|
||||
import { CheckCircle2, ExternalLink, Forward, MapPin, Ruler } from 'lucide-react'
|
||||
import { useMemo } from 'react'
|
||||
import { Alert, Box, Chip, Divider, Typography } from '@mui/material'
|
||||
import { CheckCircle2, ExternalLink, MapPin, Ruler } from 'lucide-react'
|
||||
import type { MarketLead } from '../../hooks/useMarketLeads'
|
||||
import { useCreateExposeLead } from '../../hooks/useExposeLeads'
|
||||
import { useToastStore } from '../../stores/toastStore'
|
||||
import { AgentAvatar, ObjectDeepLink } from '../team'
|
||||
import { agentWorkspaceById } from '../../lib/agentWorkspaces'
|
||||
import { SOURCE_TYPE_LABELS } from '../../lib/constants'
|
||||
@@ -30,16 +28,15 @@ const LIVIA = agentWorkspaceById('livia')!
|
||||
|
||||
interface LeadDetailProps {
|
||||
lead: MarketLead
|
||||
/** Matching-Block und Weiterleitung anzeigen. Bei Nora ja, bei Livia nein (§1). */
|
||||
/** Matching-Block anzeigen. Bei Nora ja, bei Livia nein (§1). */
|
||||
showMatching?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper, der die Detailansicht über die Signal-ID neu aufbaut.
|
||||
*
|
||||
* Damit ist die Objektauswahl an das Signal gebunden, ohne sie in einem Effekt
|
||||
* zurücksetzen zu müssen — ein neues Signal ist eine neue Komponente, und die
|
||||
* startet ohnehin ohne Auswahl.
|
||||
* Ein neues Signal ist damit eine neue Komponente und startet mit frischem
|
||||
* Zustand, statt ihn in einem Effekt zurücksetzen zu müssen.
|
||||
*/
|
||||
function LeadDetail({ lead, showMatching = true }: LeadDetailProps) {
|
||||
return <LeadDetailBody key={lead.signal.id} lead={lead} showMatching={showMatching} />
|
||||
@@ -55,10 +52,6 @@ function LeadDetailBody({ lead, showMatching }: { lead: MarketLead; showMatching
|
||||
const rationale = signalRationaleOf(signal)
|
||||
const action = recommendedActionOf(signal)
|
||||
|
||||
const forwardLead = useCreateExposeLead()
|
||||
const showToast = useToastStore(s => s.showToast)
|
||||
const [selectedIds, setSelectedIds] = useState<string[]>([])
|
||||
|
||||
// Objektvorschläge unterhalb der Schwelle werden gar nicht erst gezeigt.
|
||||
const relevant = useMemo(
|
||||
() =>
|
||||
@@ -70,29 +63,6 @@ function LeadDetailBody({ lead, showMatching }: { lead: MarketLead; showMatching
|
||||
|
||||
const contacts = useMemo(() => confirmableContacts(signal.extractedContacts), [signal.extractedContacts])
|
||||
|
||||
const toggle = useCallback((id: string) => {
|
||||
setSelectedIds(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id])
|
||||
}, [])
|
||||
|
||||
function handleForward() {
|
||||
const count = selectedIds.length
|
||||
forwardLead.mutate(
|
||||
{
|
||||
prospect: companyName,
|
||||
contacts: contacts.map(c => c.value),
|
||||
locationHint: signal.locationHint,
|
||||
propertyIds: selectedIds,
|
||||
sourceSignalId: signal.id,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
setSelectedIds([])
|
||||
showToast(`Zur Exposé-Erstellung vorgemerkt — ${count} Objekt(e) für ${companyName}.`, 'success')
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={{ height: '100%', overflowY: 'auto' }}>
|
||||
{/* Header — ohne Wahrscheinlichkeitsangabe (§7.3) */}
|
||||
@@ -270,27 +240,9 @@ function LeadDetailBody({ lead, showMatching }: { lead: MarketLead; showMatching
|
||||
Kein Portfolioobjekt über {MIN_MATCH_PCT}% Flächenmatch — manuelle Prüfung empfohlen
|
||||
</Alert>
|
||||
) : (
|
||||
<>
|
||||
{relevant.map(({ p, fit }) => (
|
||||
<SignalPropertyRow
|
||||
key={p.id}
|
||||
p={p}
|
||||
fit={fit}
|
||||
selected={selectedIds.includes(p.id)}
|
||||
onToggle={() => toggle(p.id)}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<Forward size={15} />}
|
||||
disabled={selectedIds.length === 0 || forwardLead.isPending}
|
||||
onClick={handleForward}
|
||||
sx={{ mt: 1, textTransform: 'none', bgcolor: DS_BRAND.main, '&:hover': { bgcolor: DS_BRAND.hoverAlt } }}
|
||||
>
|
||||
Für Exposé-Erstellung vormerken
|
||||
{selectedIds.length > 0 && ` (${selectedIds.length})`}
|
||||
</Button>
|
||||
</>
|
||||
relevant.map(({ p, fit }) => (
|
||||
<SignalPropertyRow key={p.id} p={p} fit={fit} />
|
||||
))
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
|
||||
Reference in new issue
Block a user