import { useEffect, useRef, useState } from 'react' import { Box, Button, CircularProgress, Dialog, DialogContent, IconButton, Stack, Step, StepLabel, Stepper, TextField, Typography, } from '@mui/material' import { Plus, Trash2, X } from 'lucide-react' import type { OfferReportDraft, ViewingAppointmentOption } from '../../domain/offerReport' import { offerReportService } from '../../services/offerReportService' import { usePropertyById } from '../../hooks/useProperties' import { useToastStore } from '../../stores/toastStore' import { OfferWizardPdfStep } from './OfferWizardPdfStep' interface Props { inquiryId: string propertyId: string tenantName: string onClose: () => void onAttach: (label: string) => void } const STEPS = ['Daten erfassen', 'Bericht prüfen', 'Besichtigungstermine', 'PDF erstellen'] export function OfferCreationWizard({ inquiryId, propertyId, tenantName, onClose, onAttach }: Props) { const [step, setStep] = useState(0) const [draft, setDraft] = useState(null) const [loading, setLoading] = useState(true) const [generating, setGenerating] = useState(false) const [progress, setProgress] = useState(0) const [ready, setReady] = useState(false) const { data: property } = usePropertyById(propertyId) const showToast = useToastStore(s => s.showToast) const timerRef = useRef | null>(null) useEffect(() => { offerReportService .create(inquiryId, propertyId, tenantName, property?.title ?? '') .then(d => { setDraft(d); setLoading(false) }) }, [inquiryId, propertyId, tenantName, property?.title]) useEffect(() => () => { if (timerRef.current) clearInterval(timerRef.current) }, []) const handleUpdateField = (fieldId: string, value: string) => { if (!draft) return setDraft({ ...draft, editableFields: draft.editableFields.map(f => f.id === fieldId ? { ...f, value } : f) }) } const addAppointment = () => { if (!draft) return const slot: ViewingAppointmentOption = { id: crypto.randomUUID(), date: new Date(Date.now() + 7 * 86_400_000).toISOString().slice(0, 10), timeSlot: '10:00–11:00', } setDraft({ ...draft, viewingAppointments: [...draft.viewingAppointments, slot] }) } const removeAppointment = (id: string) => { if (!draft) return setDraft({ ...draft, viewingAppointments: draft.viewingAppointments.filter(a => a.id !== id) }) } const updateAppointment = (id: string, field: keyof ViewingAppointmentOption, value: string) => { if (!draft) return setDraft({ ...draft, viewingAppointments: draft.viewingAppointments.map(a => a.id === id ? { ...a, [field]: value } : a, ), }) } const handleGeneratePdf = async () => { if (!draft) return await offerReportService.update(draft.id, { editableFields: draft.editableFields, viewingAppointments: draft.viewingAppointments, }) setStep(3) setGenerating(true) setProgress(0) let p = 0 timerRef.current = setInterval(() => { p += Math.random() * 18 + 8 if (p >= 100) { clearInterval(timerRef.current!) setProgress(100) setGenerating(false) setReady(true) offerReportService.generatePdf(draft.id).then(setDraft) } else { setProgress(Math.min(100, p)) } }, 200) } return ( Angebot erstellen {STEPS.map(label => ( {label} ))} {loading && ( )} {/* Step 0: Data summary */} {!loading && step === 0 && property && ( Objekt {property.images?.[0] && ( )} {property.title} {property.location.city} · {property.areaSqm.toLocaleString('de-CH')} m² · CHF {property.rentPricePerSqm}/m²/Jahr Interessent {tenantName} Das Angebot wird auf Basis der Objekt- und Anfragedaten vorausgefüllt. Im nächsten Schritt können Sie alle Felder anpassen. )} {/* Step 1: Edit fields */} {!loading && step === 1 && draft && ( {draft.editableFields.map(f => ( handleUpdateField(f.id, e.target.value)} multiline={f.fieldType === 'textarea'} rows={f.fieldType === 'textarea' ? 3 : 1} size="small" fullWidth /> ))} )} {/* Step 2: Viewing appointments */} {!loading && step === 2 && draft && ( Fügen Sie Besichtigungstermine hinzu, die dem Interessenten angeboten werden sollen: {draft.viewingAppointments.map(a => ( updateAppointment(a.id, 'date', e.target.value)} InputLabelProps={{ shrink: true }} sx={{ width: 160 }} /> updateAppointment(a.id, 'timeSlot', e.target.value)} placeholder="10:00–11:00" sx={{ width: 140 }} /> updateAppointment(a.id, 'contactPerson', e.target.value)} sx={{ flex: 1 }} /> removeAppointment(a.id)} sx={{ color: '#ef4444' }}> ))} )} {/* Step 3: PDF */} {step === 3 && ( showToast('PDF wird heruntergeladen…', 'info')} onAttach={() => { const label = `Angebot_${property?.title ?? 'Objekt'}.pdf` onAttach(label) showToast('Angebot als Anhang hinzugefügt', 'success') }} /> )} {/* Footer */} {step > 0 && step < 3 && ( )} {step === 0 && ( )} {step === 1 && ( )} {step === 2 && ( )} ) }