diff --git a/src/components/anfragencenter/OfferCreationWizard.tsx b/src/components/anfragencenter/OfferCreationWizard.tsx
index 304197d..bcae3a4 100644
--- a/src/components/anfragencenter/OfferCreationWizard.tsx
+++ b/src/components/anfragencenter/OfferCreationWizard.tsx
@@ -1,14 +1,15 @@
import { useEffect, useRef, useState } from 'react'
import {
Box, Button, CircularProgress, Dialog, DialogContent,
- IconButton, LinearProgress, Stack, Step, StepLabel, Stepper,
+ IconButton, Stack, Step, StepLabel, Stepper,
TextField, Typography,
} from '@mui/material'
-import { Download, Plus, Send, Trash2, X } from 'lucide-react'
+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
@@ -213,94 +214,19 @@ export function OfferCreationWizard({ inquiryId, propertyId, tenantName, onClose
{/* Step 3: PDF */}
{step === 3 && (
-
- {generating ? (
- <>
-
-
- PDF wird generiert…
-
-
-
-
- {Math.round(progress)}%
-
-
- >
- ) : ready ? (
-
-
-
-
-
-
-
- Angebot_{draft?.propertyId ?? 'Objekt'}.pdf
-
-
-
-
- Angebotsschreiben
-
- {draft?.editableFields.slice(0, 3).map(f => (
-
- {f.label}
-
- {f.value.slice(0, 80)}{f.value.length > 80 ? '…' : ''}
-
-
- ))}
- {(draft?.viewingAppointments.length ?? 0) > 0 && (
-
-
- Besichtigungstermine
-
- {draft!.viewingAppointments.map(a => (
-
- {new Date(a.date).toLocaleDateString('de-CH')} · {a.timeSlot}
-
- ))}
-
- )}
-
-
-
- }
- onClick={() => showToast('PDF wird heruntergeladen…', 'info')}
- sx={{ textTransform: 'none', bgcolor: '#1e3a5f', '&:hover': { bgcolor: '#16304d' } }}
- >
- Herunterladen
-
- }
- onClick={() => {
- const label = `Angebot_${property?.title ?? 'Objekt'}.pdf`
- onAttach(label)
- showToast('Angebot als Anhang hinzugefügt', 'success')
- }}
- sx={{ textTransform: 'none' }}
- >
- An Nachricht anhängen
-
-
-
- ) : null}
-
+ showToast('PDF wird heruntergeladen…', 'info')}
+ onAttach={() => {
+ const label = `Angebot_${property?.title ?? 'Objekt'}.pdf`
+ onAttach(label)
+ showToast('Angebot als Anhang hinzugefügt', 'success')
+ }}
+ />
)}
diff --git a/src/components/anfragencenter/OfferWizardPdfStep.tsx b/src/components/anfragencenter/OfferWizardPdfStep.tsx
new file mode 100644
index 0000000..91f7119
--- /dev/null
+++ b/src/components/anfragencenter/OfferWizardPdfStep.tsx
@@ -0,0 +1,103 @@
+import { Box, Button, CircularProgress, LinearProgress, Typography } from '@mui/material'
+import { Download, Send } from 'lucide-react'
+import type { OfferReportDraft } from '../../domain/offerReport'
+import type { Property } from '../../domain/property'
+
+interface OfferWizardPdfStepProps {
+ generating: boolean
+ progress: number
+ ready: boolean
+ draft: OfferReportDraft | null
+ property: Property | undefined
+ onDownload: () => void
+ onAttach: () => void
+}
+
+export function OfferWizardPdfStep({ generating, progress, ready, draft, property, onDownload, onAttach }: OfferWizardPdfStepProps) {
+ return (
+
+ {generating ? (
+ <>
+
+
+ PDF wird generiert…
+
+
+
+
+ {Math.round(progress)}%
+
+
+ >
+ ) : ready ? (
+
+
+
+
+
+
+
+ Angebot_{property?.title ?? 'Objekt'}.pdf
+
+
+
+
+ Angebotsschreiben
+
+ {draft?.editableFields.slice(0, 3).map(f => (
+
+ {f.label}
+
+ {f.value.slice(0, 80)}{f.value.length > 80 ? '…' : ''}
+
+
+ ))}
+ {(draft?.viewingAppointments.length ?? 0) > 0 && (
+
+
+ Besichtigungstermine
+
+ {draft!.viewingAppointments.map(a => (
+
+ {new Date(a.date).toLocaleDateString('de-CH')} · {a.timeSlot}
+
+ ))}
+
+ )}
+
+
+
+ }
+ onClick={onDownload}
+ sx={{ textTransform: 'none', bgcolor: '#1e3a5f', '&:hover': { bgcolor: '#16304d' } }}
+ >
+ Herunterladen
+
+ }
+ onClick={onAttach}
+ sx={{ textTransform: 'none' }}
+ >
+ An Nachricht anhängen
+
+
+
+ ) : null}
+
+ )
+}
diff --git a/src/components/supply/ReminderDetailDrawer.tsx b/src/components/supply/ReminderDetailDrawer.tsx
index 6b4614b..d0d78dc 100644
--- a/src/components/supply/ReminderDetailDrawer.tsx
+++ b/src/components/supply/ReminderDetailDrawer.tsx
@@ -18,91 +18,8 @@ import { useReminder, useCompleteReminder, useDismissReminder, useSnoozeReminder
import { ReminderPriorityBadge } from './ReminderPriorityBadge'
import { ReminderTypeBadge } from './ReminderTypeBadge'
import { ReminderDaysIndicator } from './ReminderDaysIndicator'
-import { ReminderStatus, ShadowMarketRisk } from '../../domain/reminder'
-import type { ReminderActivity } from '../../domain/reminder'
-
-const SHADOW_RISK_COLOR: Record = {
- NONE: '#64748b',
- LOW: '#16a34a',
- MEDIUM: '#ca8a04',
- HIGH: '#dc2626',
-}
-
-const SHADOW_RISK_LABEL: Record = {
- NONE: 'Kein Risiko',
- LOW: 'Niedrig',
- MEDIUM: 'Mittel',
- HIGH: 'Hoch',
-}
-
-const STATUS_CHIP_COLOR: Record = {
- ACTIVE: 'info',
- SNOOZED: 'warning',
- COMPLETED: 'success',
- DISMISSED: 'default',
-}
-
-const STATUS_LABEL: Record = {
- ACTIVE: 'Aktiv',
- SNOOZED: 'Schlummernd',
- COMPLETED: 'Erledigt',
- DISMISSED: 'Verworfen',
-}
-
-const ACTION_LABEL: Record = {
- CREATED: 'Erstellt',
- SNOOZED: 'Zurückgestellt',
- COMPLETED: 'Erledigt',
- DISMISSED: 'Verworfen',
- NOTED: 'Notiz',
-}
-
-function SectionTitle({ icon, children }: { icon: React.ReactNode; children: React.ReactNode }) {
- return (
-
- {icon}
-
- {children}
-
-
- )
-}
-
-function DateRow({ label, value }: { label: string; value?: string }) {
- if (!value) return null
- return (
-
- {label}
- {new Date(value).toLocaleDateString('de-CH')}
-
- )
-}
-
-function ActivityEntry({ entry }: { entry: ReminderActivity }) {
- return (
-
-
-
-
-
-
-
-
- {ACTION_LABEL[entry.action]}
-
-
- {entry.by} · {new Date(entry.at).toLocaleDateString('de-CH')}
-
-
- {entry.note && (
-
- {entry.note}
-
- )}
-
-
- )
-}
+import { ReminderStatus } from '../../domain/reminder'
+import { SHADOW_RISK_COLOR, SHADOW_RISK_LABEL, STATUS_CHIP_COLOR, STATUS_LABEL, ACTION_LABEL, SectionTitle, DateRow, ActivityEntry } from './reminderDetailHelpers'
export function ReminderDetailDrawer() {
const { selectedId, drawerOpen, setDrawerOpen, setSelectedId } = useReminderStore()
diff --git a/src/components/supply/reminderDetailHelpers.tsx b/src/components/supply/reminderDetailHelpers.tsx
new file mode 100644
index 0000000..df454ff
--- /dev/null
+++ b/src/components/supply/reminderDetailHelpers.tsx
@@ -0,0 +1,85 @@
+import { Box, Typography } from '@mui/material'
+import type { ReminderActivity } from '../../domain/reminder'
+
+export const SHADOW_RISK_COLOR: Record = {
+ NONE: '#64748b',
+ LOW: '#16a34a',
+ MEDIUM: '#ca8a04',
+ HIGH: '#dc2626',
+}
+
+export const SHADOW_RISK_LABEL: Record = {
+ NONE: 'Kein Risiko',
+ LOW: 'Niedrig',
+ MEDIUM: 'Mittel',
+ HIGH: 'Hoch',
+}
+
+export const STATUS_CHIP_COLOR: Record = {
+ ACTIVE: 'info',
+ SNOOZED: 'warning',
+ COMPLETED: 'success',
+ DISMISSED: 'default',
+}
+
+export const STATUS_LABEL: Record = {
+ ACTIVE: 'Aktiv',
+ SNOOZED: 'Schlummernd',
+ COMPLETED: 'Erledigt',
+ DISMISSED: 'Verworfen',
+}
+
+export const ACTION_LABEL: Record = {
+ CREATED: 'Erstellt',
+ SNOOZED: 'Zurückgestellt',
+ COMPLETED: 'Erledigt',
+ DISMISSED: 'Verworfen',
+ NOTED: 'Notiz',
+}
+
+export function SectionTitle({ icon, children }: { icon: React.ReactNode; children: React.ReactNode }) {
+ return (
+
+ {icon}
+
+ {children}
+
+
+ )
+}
+
+export function DateRow({ label, value }: { label: string; value?: string }) {
+ if (!value) return null
+ return (
+
+ {label}
+ {new Date(value).toLocaleDateString('de-CH')}
+
+ )
+}
+
+export function ActivityEntry({ entry }: { entry: ReminderActivity }) {
+ return (
+
+
+
+
+
+
+
+
+ {ACTION_LABEL[entry.action]}
+
+
+ {entry.by} · {new Date(entry.at).toLocaleDateString('de-CH')}
+
+
+ {entry.note && (
+
+ {entry.note}
+
+ )}
+
+
+ )
+}