feat: Inserat erstellen — direct listing flow for units and standalone

- New /supply/new-listing page (Path A: pre-filled from portfolio unit,
  Path B: standalone blank form); creates EXTERNAL_MARKET + sourceType DIRECT
- "+ Inserat" button on available units in PropertyDetailView navigates
  with prefilled address/area/rent
- Nav entry "Neues Inserat" added to supply sidebar
- SourceProvenancePanel hidden for DIRECT source listings (no external source)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-21 21:10:41 +02:00
parent 531c88cfb6
commit 67d3d06a53
5 changed files with 338 additions and 0 deletions
@@ -106,6 +106,7 @@ function MatchPill({ m }: { m: UnitNeedMatch }) {
}
function UnitStructurePanel({ p }: { p: Property }) {
const navigate = useNavigate()
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set())
const [expandedUnit, setExpandedUnit] = useState<string | null>(null)
@@ -204,6 +205,28 @@ function UnitStructurePanel({ p }: { p: Property }) {
{u.isFlexible && (
<Chip label="Teilfläche möglich" size="small" sx={{ height: 16, fontSize: '0.58rem', bgcolor: '#eff6ff', color: '#1d4ed8', border: '1px solid #bfdbfe' }} />
)}
<Button
size="small"
variant="text"
sx={{ height: 16, fontSize: '0.58rem', p: 0, minWidth: 0, color: '#7c3aed', textTransform: 'none', lineHeight: 1 }}
onClick={() => navigate('/supply/new-listing', {
state: {
prefill: {
assetType: p.assetType,
street: p.address?.street,
houseNumber: p.address?.houseNumber,
postalCode: p.address?.postalCode,
city: p.address?.city,
areaSqm: u.offeredSqm ?? u.areaSqm,
rentPricePerSqm: u.rentPricePerSqm ?? p.rentPricePerSqm,
unitLabel: u.unitLabel,
propertyId: p.id,
},
},
})}
>
+ Inserat
</Button>
</>
) : (
<Typography variant="caption" sx={{ color: '#64748b' }} noWrap>{u.currentTenant ?? 'Vermietet'}</Typography>