feat: Mietvertrag hinterlegen pro Objekt (Link + Bezeichnung)
- Property.leaseContractUrl? + leaseContractName? im Domain - PropertyDetailOverview: Mietvertrag-Block in "Miet- & Mieterinformationen" — View-Modus: Öffnen-Button oder "Noch kein Vertrag"-Hinweis — Edit-Modus: URL-Feld + Bezeichnungsfeld (gespeichert via updateProperty) - ReminderDetailDrawer: Mietvertrag-Link im "Objekt"-Abschnitt (lädt Property über usePropertyById) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Box, Divider, LinearProgress, TextField, Typography } from '@mui/material'
|
||||
import { Box, Button, Divider, LinearProgress, TextField, Typography } from '@mui/material'
|
||||
import { ExternalLink, FileText, Plus } from 'lucide-react'
|
||||
import type { Property, UpdatePropertyInput } from '../../domain/property'
|
||||
import { PropertyMap } from '../shared'
|
||||
import { getAssetTypeLabel, qualityColor } from './propertyHelpers'
|
||||
@@ -97,18 +98,75 @@ export function PropertyDetailOverview({ p, editing, draft, onDraftChange }: Pro
|
||||
onChange={e => onDraftChange({ ...draft, leaseEndDate: e.target.value })}
|
||||
/>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, mt: 0.5, mb: 0.5 }}>
|
||||
<FileText size={13} color="#64748b" />
|
||||
<Typography variant="caption" sx={{ fontWeight: 700, color: '#64748b', textTransform: 'uppercase', letterSpacing: 0.4 }}>
|
||||
Mietvertrag
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 1.5 }}>
|
||||
<TextField
|
||||
label="Vertrag URL"
|
||||
size="small"
|
||||
value={draft.leaseContractUrl ?? p.leaseContractUrl ?? ''}
|
||||
onChange={e => onDraftChange({ ...draft, leaseContractUrl: e.target.value })}
|
||||
placeholder="https://…"
|
||||
slotProps={{ input: { startAdornment: <ExternalLink size={12} style={{ marginRight: 6, color: '#94a3b8', flexShrink: 0 }} /> } }}
|
||||
/>
|
||||
<TextField
|
||||
label="Bezeichnung (optional)"
|
||||
size="small"
|
||||
value={draft.leaseContractName ?? p.leaseContractName ?? ''}
|
||||
onChange={e => onDraftChange({ ...draft, leaseContractName: e.target.value })}
|
||||
placeholder="z.B. Mietvertrag 2021–2026"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
) : (
|
||||
<FieldGrid>
|
||||
<Field label="Aktueller Mieter" value={p.currentTenant} />
|
||||
<Field label="Mietlaufzeit" value={p.leaseTerm} />
|
||||
<Field label="Mietbeginn" value={p.leaseStartDate ? new Date(p.leaseStartDate).toLocaleDateString('de-CH') : undefined} />
|
||||
<Field label="Mietende" value={p.leaseEndDate ? new Date(p.leaseEndDate).toLocaleDateString('de-CH') : undefined} />
|
||||
<Field label="Breakoutoption" value={p.breakoutOption} />
|
||||
<Field label="Breakoutoption Zeitpunkt" value={p.breakoutOptionDate ? new Date(p.breakoutOptionDate).toLocaleDateString('de-CH') : undefined} />
|
||||
<Field label="Importiert aus" value={p.importedFrom} />
|
||||
<Field label="Zuletzt aktualisiert" value={p.lastUpdatedAt ? new Date(p.lastUpdatedAt).toLocaleDateString('de-CH') : undefined} />
|
||||
</FieldGrid>
|
||||
<>
|
||||
<FieldGrid>
|
||||
<Field label="Aktueller Mieter" value={p.currentTenant} />
|
||||
<Field label="Mietlaufzeit" value={p.leaseTerm} />
|
||||
<Field label="Mietbeginn" value={p.leaseStartDate ? new Date(p.leaseStartDate).toLocaleDateString('de-CH') : undefined} />
|
||||
<Field label="Mietende" value={p.leaseEndDate ? new Date(p.leaseEndDate).toLocaleDateString('de-CH') : undefined} />
|
||||
<Field label="Breakoutoption" value={p.breakoutOption} />
|
||||
<Field label="Breakoutoption Zeitpunkt" value={p.breakoutOptionDate ? new Date(p.breakoutOptionDate).toLocaleDateString('de-CH') : undefined} />
|
||||
<Field label="Importiert aus" value={p.importedFrom} />
|
||||
<Field label="Zuletzt aktualisiert" value={p.lastUpdatedAt ? new Date(p.lastUpdatedAt).toLocaleDateString('de-CH') : undefined} />
|
||||
</FieldGrid>
|
||||
|
||||
{/* Mietvertrag */}
|
||||
<Box sx={{ mt: 1.5, p: 1.5, border: '1px solid #e2e8f0', borderRadius: 1.5, bgcolor: p.leaseContractUrl ? '#f8fafc' : '#fafafa' }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, mb: p.leaseContractUrl ? 0.75 : 0 }}>
|
||||
<FileText size={13} color={p.leaseContractUrl ? '#1e3a5f' : '#94a3b8'} />
|
||||
<Typography variant="caption" sx={{ fontWeight: 700, color: p.leaseContractUrl ? '#1e3a5f' : '#94a3b8', textTransform: 'uppercase', letterSpacing: 0.4 }}>
|
||||
Mietvertrag
|
||||
</Typography>
|
||||
</Box>
|
||||
{p.leaseContractUrl ? (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1 }}>
|
||||
<Typography variant="caption" sx={{ color: '#475569', fontWeight: 500 }} noWrap>
|
||||
{p.leaseContractName ?? 'Mietvertrag'}
|
||||
</Typography>
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
endIcon={<ExternalLink size={11} />}
|
||||
href={p.leaseContractUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
sx={{ textTransform: 'none', fontSize: '0.7rem', py: 0.25, px: 1, borderColor: '#cbd5e1', color: '#1e3a5f', whiteSpace: 'nowrap', flexShrink: 0 }}
|
||||
>
|
||||
Öffnen
|
||||
</Button>
|
||||
</Box>
|
||||
) : (
|
||||
<Typography variant="caption" sx={{ color: '#94a3b8' }}>
|
||||
Noch kein Mietvertrag hinterlegt — im Bearbeitungsmodus hinzufügen.
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Floor / unit structure */}
|
||||
|
||||
@@ -12,9 +12,10 @@ import {
|
||||
FormControlLabel,
|
||||
Tooltip,
|
||||
} from '@mui/material'
|
||||
import { X, MapPin, Calendar, DollarSign, Eye, Activity } from 'lucide-react'
|
||||
import { X, MapPin, Calendar, DollarSign, Eye, Activity, FileText, ExternalLink } from 'lucide-react'
|
||||
import { useReminderStore } from '../../stores/reminderStore'
|
||||
import { useReminder, useCompleteReminder, useDismissReminder, useSnoozeReminder } from '../../hooks/useReminders'
|
||||
import { usePropertyById } from '../../hooks/useProperties'
|
||||
import { ReminderPriorityBadge } from './ReminderPriorityBadge'
|
||||
import { ReminderTypeBadge } from './ReminderTypeBadge'
|
||||
import { ReminderDaysIndicator } from './ReminderDaysIndicator'
|
||||
@@ -24,6 +25,7 @@ import { SHADOW_RISK_COLOR, SHADOW_RISK_LABEL, STATUS_CHIP_COLOR, STATUS_LABEL,
|
||||
export function ReminderDetailDrawer() {
|
||||
const { selectedId, drawerOpen, setDrawerOpen, setSelectedId } = useReminderStore()
|
||||
const { data: reminder } = useReminder(selectedId ?? '')
|
||||
const { data: reminderProperty } = usePropertyById(reminder?.propertyId ?? '')
|
||||
const complete = useCompleteReminder()
|
||||
const dismiss = useDismissReminder()
|
||||
const snooze = useSnoozeReminder()
|
||||
@@ -101,6 +103,27 @@ export function ReminderDetailDrawer() {
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary">Mieter: {reminder.tenantName}</Typography>
|
||||
<Typography variant="caption" color="text.secondary">Fläche: {reminder.areaSqm.toLocaleString('de-CH')} m²</Typography>
|
||||
{reminderProperty?.leaseContractUrl ? (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.75, mt: 0.5 }}>
|
||||
<FileText size={12} color="#1e3a5f" />
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
endIcon={<ExternalLink size={10} />}
|
||||
href={reminderProperty.leaseContractUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
sx={{ textTransform: 'none', fontSize: '0.68rem', py: 0.125, px: 0.75, borderColor: '#cbd5e1', color: '#1e3a5f' }}
|
||||
>
|
||||
{reminderProperty.leaseContractName ?? 'Mietvertrag'}
|
||||
</Button>
|
||||
</Box>
|
||||
) : (
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mt: 0.5 }}>
|
||||
<FileText size={12} color="#cbd5e1" />
|
||||
<Typography variant="caption" sx={{ color: '#cbd5e1' }}>Kein Mietvertrag hinterlegt</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
|
||||
@@ -135,6 +135,8 @@ export interface Property {
|
||||
description?: string
|
||||
images?: string[]
|
||||
floorPlanUrl?: string
|
||||
leaseContractUrl?: string // link to the signed lease document
|
||||
leaseContractName?: string // display label, e.g. "Mietvertrag 2021–2026"
|
||||
|
||||
propertyNumber?: string
|
||||
units?: PropertyUnit[]
|
||||
|
||||
Reference in New Issue
Block a user