diff --git a/src/App.tsx b/src/App.tsx
index fe53ef2..e453573 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -32,6 +32,7 @@ const Results = lazy(() => import('./pages/demand/Results'))
const MatchDetail = lazy(() => import('./pages/demand/MatchDetail'))
const Compare = lazy(() => import('./pages/demand/Compare'))
const Shortlists = lazy(() => import('./pages/demand/Shortlists'))
+const Pipeline = lazy(() => import('./pages/demand/Pipeline'))
const ReviewQueue = lazy(() => import('./pages/ops/ReviewQueue'))
const AIMonitoring = lazy(() => import('./pages/ops/AIMonitoring'))
@@ -71,6 +72,7 @@ function App() {
} />
} />
} />
+ } />
{/* Operations Workspace */}
diff --git a/src/components/anfragencenter/OfferPdfReviewStep.tsx b/src/components/anfragencenter/OfferPdfReviewStep.tsx
index 1a45c84..efc833d 100644
--- a/src/components/anfragencenter/OfferPdfReviewStep.tsx
+++ b/src/components/anfragencenter/OfferPdfReviewStep.tsx
@@ -1,9 +1,8 @@
import { useEffect, useMemo, useState } from 'react'
import { Box, Button, CircularProgress, Typography } from '@mui/material'
-import { ArrowLeft, ArrowRight } from 'lucide-react'
+import { ArrowLeft, Send } from 'lucide-react'
import { useOfferWizardStore } from '../../stores/offerWizardStore'
-import { offerService } from '../../services/offerService'
-import { useUpdateOfferField, useGeneratePdfPreview } from '../../hooks/useOffers'
+import { useUpdateOfferField, useGeneratePdfPreview, useMarkOfferChecked } from '../../hooks/useOffers'
import { useToastStore } from '../../stores/toastStore'
import { MockPdfPreview } from './MockPdfPreview'
import { EditableOfferFieldList } from './EditableOfferFieldList'
@@ -22,6 +21,7 @@ export function OfferPdfReviewStep() {
const updateFieldMut = useUpdateOfferField()
const genPreview = useGeneratePdfPreview()
+ const markChecked = useMarkOfferChecked()
const showToast = useToastStore(s => s.showToast)
useEffect(() => {
@@ -66,13 +66,34 @@ export function OfferPdfReviewStep() {
}
}
- const handleNext = () => {
+ const needTitle = useOfferWizardStore(s => s.needTitle)
+ const addAttachment = useOfferWizardStore(s => s.addAttachment)
+ const setMessageDraft = useOfferWizardStore(s => s.setMessageDraft)
+ const setMessageSubject = useOfferWizardStore(s => s.setMessageSubject)
+
+ const handleNext = async () => {
if (!offerDraftId) return
if (!pdfReady) {
showToast('PDF-Vorschau wird noch generiert...', 'info')
return
}
- setStep('checked')
+ const res = await markChecked.mutateAsync(offerDraftId)
+ if (res.error) {
+ showToast(`Fehler: ${res.error}`, 'error')
+ return
+ }
+ addAttachment({
+ id: crypto.randomUUID(),
+ fileName: `Angebot_${needTitle.replace(/\s+/g, '_')}.pdf`,
+ fileType: 'application/pdf',
+ fileSize: 320_000,
+ generated: true,
+ })
+ setMessageSubject(`Passende Gewerbeflächen zu Ihrer Anfrage: ${needTitle}`)
+ setMessageDraft(
+ `Sehr geehrte Damen und Herren,\n\nbitte finden Sie anbei unser Angebot zu Ihrem Bedarf "${needTitle}". Gerne stehen wir für Rückfragen und Besichtigungstermine zur Verfügung.\n\nFreundliche Grüsse\nWincasa AG`,
+ )
+ setStep('send')
}
if (loadingDraft || !draft) {
@@ -153,12 +174,12 @@ export function OfferPdfReviewStep() {
}
+ endIcon={markChecked.isPending ? : }
onClick={handleNext}
- disabled={!pdfReady}
+ disabled={!pdfReady || markChecked.isPending}
sx={{ textTransform: 'none', bgcolor: '#1e3a5f', '&:hover': { bgcolor: '#16304d' } }}
>
- Angebot prüfen
+ {markChecked.isPending ? 'Wird geprüft…' : 'Angebot senden →'}
diff --git a/src/components/anfragencenter/OfferWizard.tsx b/src/components/anfragencenter/OfferWizard.tsx
index 93abe37..846852d 100644
--- a/src/components/anfragencenter/OfferWizard.tsx
+++ b/src/components/anfragencenter/OfferWizard.tsx
@@ -16,13 +16,20 @@ import { OfferPdfReviewStep } from './OfferPdfReviewStep'
import { OfferCheckedAction } from './OfferCheckedAction'
import { OfferChatComposer } from './OfferChatComposer'
+// 'checked' is internal — merged into pdf_review step; only 3 steps shown
const STEPS: { key: OfferStep; label: string }[] = [
{ key: 'select_properties', label: 'Objekte wählen' },
- { key: 'pdf_review', label: 'PDF-Vorschau' },
- { key: 'checked', label: 'Prüfen' },
- { key: 'send', label: 'Senden' },
+ { key: 'pdf_review', label: 'Vorschau & Prüfen' },
+ { key: 'send', label: 'Senden' },
]
+const STEP_DISPLAY_INDEX: Record = {
+ select_properties: 0,
+ pdf_review: 1,
+ checked: 1, // same visual step as pdf_review
+ send: 2,
+}
+
export function OfferWizard() {
const theme = useTheme()
const fullScreen = useMediaQuery(theme.breakpoints.down('md'))
@@ -32,7 +39,7 @@ export function OfferWizard() {
const currentStep = useOfferWizardStore(s => s.currentStep)
const needTitle = useOfferWizardStore(s => s.needTitle)
- const activeIndex = STEPS.findIndex(s => s.key === currentStep)
+ const activeIndex = STEP_DISPLAY_INDEX[currentStep] ?? 0
return (