c4c29ef7d3
Neuer Menüpunkt «Anfragencenter» (ehemals «Eingehende Bedarfe»): Aktive Anfragen: - Split-View: Anfrageliste (Liste/Grid-Toggle) + Chat-Detailansicht - Chat-Verlauf mit Sender-Styling (Mieter links, Supply rechts) - Antwortformular mit Betreff, Nachricht, Anhänge, Statuswechsel - Zugehörige Property Card neben dem Chat Latente Anfragen: - Drei-Spalten-Layout: Need-Liste | Need-Detail | Eigene Objekte - Need Cards mit AI-Zusammenfassung, Must-Haves, Präferenzen - Eigene Portfolio-Objekte sortiert nach deterministischem Match-Score - Checkbox-Selektion für Angebotsauswahl Angebot-Wizard (4 Schritte): - Schritt 1: Objekte auswählen (mit Score-Vorschau) - Schritt 2: PDF-Vorschau + editierbare Textfelder - Schritt 3: Angebot prüfen & bestätigen - Schritt 4: Nachricht an Suchenden mit KI-generierter Mail Architektur: - Domain: Inquiry, LatentNeed, OfferDraft Types - Provider: IInquiryProvider, ILatentNeedProvider, IOfferProvider + Mockups - Services: inquiryService, latentNeedService, offerService - Hooks: useInquiries, useLatentNeeds, useOffers (TanStack Query) - Store: offerWizardStore (Zustand, lokaler Wizard-State) - 27 neue Komponenten, alle Loading/Empty/Error States Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
import { Box, TextField, Typography } from '@mui/material'
|
|
import type { OfferEditableField } from '../../domain/offer'
|
|
|
|
interface EditableOfferFieldListProps {
|
|
fields: OfferEditableField[]
|
|
values: Record<string, string>
|
|
onChange: (id: string, value: string) => void
|
|
}
|
|
|
|
export function EditableOfferFieldList({ fields, values, onChange }: EditableOfferFieldListProps) {
|
|
return (
|
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
|
|
{fields.map(f => {
|
|
const value = values[f.id] !== undefined ? values[f.id] : f.value
|
|
return (
|
|
<Box key={f.id}>
|
|
<Typography
|
|
variant="caption"
|
|
sx={{
|
|
color: '#64748b',
|
|
fontWeight: 600,
|
|
fontSize: '0.7rem',
|
|
textTransform: 'uppercase',
|
|
letterSpacing: 0.5,
|
|
mb: 0.5,
|
|
display: 'block',
|
|
}}
|
|
>
|
|
{f.label}
|
|
</Typography>
|
|
<TextField
|
|
fullWidth
|
|
size="small"
|
|
value={value}
|
|
onChange={e => onChange(f.id, e.target.value)}
|
|
multiline={f.fieldType === 'textarea'}
|
|
rows={f.fieldType === 'textarea' ? 3 : undefined}
|
|
sx={{
|
|
'& .MuiInputBase-input': { fontSize: '0.85rem' },
|
|
}}
|
|
/>
|
|
</Box>
|
|
)
|
|
})}
|
|
</Box>
|
|
)
|
|
}
|