Hocks Mieterportal: 5 Module (Dashboard, Mietkonto, Schadensmeldungen, Dokumente, Nachrichten), Docker-Setup, eigenes Branding
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
import type {
|
||||
Unit,
|
||||
Transaction,
|
||||
Ticket,
|
||||
DocumentItem,
|
||||
Thread,
|
||||
Announcement,
|
||||
} from '../types'
|
||||
|
||||
const buildings = [
|
||||
{ name: 'Hauptstraße 12', prefix: 'HS', count: 20, baseRent: 9.8 },
|
||||
{ name: 'Ringweg 3', prefix: 'RW', count: 15, baseRent: 8.9 },
|
||||
{ name: 'Am Park 5', prefix: 'AP', count: 15, baseRent: 10.4 },
|
||||
]
|
||||
|
||||
const firstNames = [
|
||||
'Anna', 'Jonas', 'Marta', 'Leon', 'Sofia', 'Felix', 'Lena', 'Paul',
|
||||
'Emma', 'Noah', 'Clara', 'Ben', 'Nora', 'Max', 'Julia', 'Tim',
|
||||
'Sarah', 'Finn', 'Laura', 'Jan', 'Mia', 'Tom', 'Ela', 'Kim',
|
||||
]
|
||||
const lastNames = [
|
||||
'Berger', 'Klein', 'Wolf', 'Neumann', 'Schäfer', 'Krüger', 'Brandt',
|
||||
'Vogel', 'Otto', 'Horn', 'Busch', 'Thomas', 'Pohl', 'Sander', 'Lindner',
|
||||
]
|
||||
|
||||
// Demo-Mieter: Whg. Hauptstraße 12 Nr. 7
|
||||
export const DEMO_TENANT = 'Anna Berger'
|
||||
export const DEMO_UNIT_ID = 'hs-7'
|
||||
|
||||
let nameIdx = 0
|
||||
function nextName(): string {
|
||||
const n = `${firstNames[nameIdx % firstNames.length]} ${lastNames[nameIdx % lastNames.length]}`
|
||||
nameIdx++
|
||||
return n
|
||||
}
|
||||
|
||||
export const units: Unit[] = buildings.flatMap((b) =>
|
||||
Array.from({ length: b.count }, (_, i) => {
|
||||
const num = i + 1
|
||||
const size = 38 + ((num * 7 + b.prefix.length * 3) % 78) // 38–115 m²
|
||||
const coldRent = Math.round(size * b.baseRent)
|
||||
const warmRent = coldRent + Math.round(2.4 * size) + (num % 3 === 0 ? 35 : 0)
|
||||
const floor = num <= 2 ? 0 : Math.min(4, Math.floor((num - 1) / 4))
|
||||
const occupied = num % 9 !== 0 // ~89 % Vermietung -> 50 Wohnungen, ~5 frei
|
||||
const tenant =
|
||||
b.prefix === 'HS' && num === 7
|
||||
? DEMO_TENANT
|
||||
: occupied
|
||||
? nextName()
|
||||
: null
|
||||
return {
|
||||
id: `${b.prefix.toLowerCase()}-${num}`,
|
||||
building: b.name,
|
||||
number: `${num}`,
|
||||
floor,
|
||||
size,
|
||||
coldRent,
|
||||
warmRent,
|
||||
tenant,
|
||||
status: occupied ? ('vermietet' as const) : ('frei' as const),
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
const monthNames = [
|
||||
'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
|
||||
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember',
|
||||
]
|
||||
|
||||
export const transactions: Transaction[] = units
|
||||
.filter((u) => u.status === 'vermietet')
|
||||
.flatMap((u) => {
|
||||
const txs: Transaction[] = []
|
||||
for (let m = 0; m < 12; m++) {
|
||||
const dueMonth = m + 1
|
||||
txs.push({
|
||||
id: `tx-${u.id}-${m}`,
|
||||
unitId: u.id,
|
||||
tenant: u.tenant!,
|
||||
month: monthNames[m],
|
||||
year: 2026,
|
||||
amount: u.warmRent,
|
||||
type: 'Miete',
|
||||
status:
|
||||
dueMonth <= 9
|
||||
? (u.id.charCodeAt(3) + m) % 11 === 0
|
||||
? 'überfällig'
|
||||
: 'bezahlt'
|
||||
: dueMonth === 10
|
||||
? 'offen'
|
||||
: 'offen',
|
||||
paidAt:
|
||||
dueMonth <= 9 && (u.id.charCodeAt(3) + m) % 11 !== 0
|
||||
? `0${(m % 8) + 1}.0${dueMonth}.2026`
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
return txs
|
||||
})
|
||||
|
||||
export const tickets: Ticket[] = [
|
||||
{
|
||||
id: 't-1',
|
||||
unitId: DEMO_UNIT_ID,
|
||||
tenant: DEMO_TENANT,
|
||||
title: 'Wasserhahn im Bad tropft',
|
||||
description:
|
||||
'Der Wasserhahn am Waschbecken tropft seit einigen Tagen permanent, auch bei ganz zugedrehtem Ventil.',
|
||||
category: 'Sanitär',
|
||||
priority: 'mittel',
|
||||
status: 'in Bearbeitung',
|
||||
createdAt: '28.09.2026',
|
||||
},
|
||||
{
|
||||
id: 't-2',
|
||||
unitId: DEMO_UNIT_ID,
|
||||
tenant: DEMO_TENANT,
|
||||
title: 'Briefkastenschlüssel defekt',
|
||||
description: 'Der Schlüssel für den Briefkasten lässt sich nicht mehr drehen, vermutlich Schloss verklebt.',
|
||||
category: 'Schlüssel',
|
||||
priority: 'niedrig',
|
||||
status: 'offen',
|
||||
createdAt: '30.09.2026',
|
||||
},
|
||||
{
|
||||
id: 't-3',
|
||||
unitId: 'rw-4',
|
||||
tenant: units.find((u) => u.id === 'rw-4')?.tenant ?? '',
|
||||
title: 'Heizkörper wird nicht warm',
|
||||
description: 'Der Heizkörper im Wohnzimmer bleibt kalt, obwohl das Thermostat voll aufgedreht ist.',
|
||||
category: 'Heizung',
|
||||
priority: 'hoch',
|
||||
status: 'offen',
|
||||
createdAt: '01.10.2026',
|
||||
},
|
||||
{
|
||||
id: 't-4',
|
||||
unitId: 'ap-2',
|
||||
tenant: units.find((u) => u.id === 'ap-2')?.tenant ?? '',
|
||||
title: 'Rollladen im Schlafzimmer klemmt',
|
||||
description: 'Der elektrische Rollladen fährt nur noch zur Hälfte hoch.',
|
||||
category: 'Fenster / Rollladen',
|
||||
priority: 'mittel',
|
||||
status: 'in Bearbeitung',
|
||||
createdAt: '25.09.2026',
|
||||
},
|
||||
{
|
||||
id: 't-5',
|
||||
unitId: 'hs-14',
|
||||
tenant: units.find((u) => u.id === 'hs-14')?.tenant ?? '',
|
||||
title: 'Flurbeleuchtung im Treppenhaus defekt',
|
||||
description: 'Im 3. OG ist die Bewegungsmelder-Leuchte ausgefallen.',
|
||||
category: 'Elektrik',
|
||||
priority: 'hoch',
|
||||
status: 'erledigt',
|
||||
createdAt: '18.09.2026',
|
||||
},
|
||||
{
|
||||
id: 't-6',
|
||||
unitId: 'rw-9',
|
||||
tenant: units.find((u) => u.id === 'rw-9')?.tenant ?? '',
|
||||
title: 'Schimmel im Bad – Lüftungsproblem?',
|
||||
description: 'In der Fensterfalz des Bades sammelt sich Kondenswasser, bitte um Prüfung der Lüftung.',
|
||||
category: 'Sanitär',
|
||||
priority: 'hoch',
|
||||
status: 'in Bearbeitung',
|
||||
createdAt: '22.09.2026',
|
||||
},
|
||||
{
|
||||
id: 't-7',
|
||||
unitId: 'ap-11',
|
||||
tenant: units.find((u) => u.id === 'ap-11')?.tenant ?? '',
|
||||
title: 'Markise auf dem Balkon lose',
|
||||
description: 'Die Befestigung der Markise wackelt bei Wind deutlich.',
|
||||
category: 'Balkon / Außenanlage',
|
||||
priority: 'hoch',
|
||||
status: 'offen',
|
||||
createdAt: '29.09.2026',
|
||||
},
|
||||
{
|
||||
id: 't-8',
|
||||
unitId: 'hs-3',
|
||||
tenant: units.find((u) => u.id === 'hs-3')?.tenant ?? '',
|
||||
title: 'Spülmaschinen-Anschluss undicht',
|
||||
description: 'Unter der Spüle steht Wasser, vermutlich kommt es vom Geräteanschluss.',
|
||||
category: 'Sanitär',
|
||||
priority: 'mittel',
|
||||
status: 'erledigt',
|
||||
createdAt: '10.09.2026',
|
||||
},
|
||||
]
|
||||
|
||||
export const documents: DocumentItem[] = [
|
||||
{
|
||||
id: 'd-1',
|
||||
unitId: DEMO_UNIT_ID,
|
||||
title: 'Mietvertrag Anna Berger – Hauptstraße 12, Whg. 7',
|
||||
category: 'Mietvertrag',
|
||||
size: '1,8 MB',
|
||||
date: '01.03.2024',
|
||||
},
|
||||
{
|
||||
id: 'd-2',
|
||||
unitId: DEMO_UNIT_ID,
|
||||
title: 'Nebenkostenabrechnung 2025',
|
||||
category: 'Nebenkostenabrechnung',
|
||||
size: '640 KB',
|
||||
date: '31.05.2026',
|
||||
},
|
||||
{
|
||||
id: 'd-3',
|
||||
unitId: DEMO_UNIT_ID,
|
||||
title: 'Heizkostenabrechnung 2025',
|
||||
category: 'Nebenkostenabrechnung',
|
||||
size: '410 KB',
|
||||
date: '31.05.2026',
|
||||
},
|
||||
{
|
||||
id: 'd-4',
|
||||
unitId: null,
|
||||
title: 'Hausordnung – gültige Fassung 2026',
|
||||
category: 'Hausordnung',
|
||||
size: '220 KB',
|
||||
date: '01.01.2026',
|
||||
},
|
||||
{
|
||||
id: 'd-5',
|
||||
unitId: null,
|
||||
title: 'Protokoll Hausversammlung 14.06.2026',
|
||||
category: 'Protokoll',
|
||||
size: '350 KB',
|
||||
date: '14.06.2026',
|
||||
},
|
||||
{
|
||||
id: 'd-6',
|
||||
unitId: null,
|
||||
title: 'Mülltonnen-Belegungsplan & Abfuhrtermine 2026',
|
||||
category: 'Sonstiges',
|
||||
size: '180 KB',
|
||||
date: '02.01.2026',
|
||||
},
|
||||
{
|
||||
id: 'd-7',
|
||||
unitId: 'rw-4',
|
||||
title: 'Mietvertrag – Ringweg 3, Whg. 4',
|
||||
category: 'Mietvertrag',
|
||||
size: '1,6 MB',
|
||||
date: '15.08.2025',
|
||||
},
|
||||
{
|
||||
id: 'd-8',
|
||||
unitId: 'ap-2',
|
||||
title: 'Mietvertrag – Am Park 5, Whg. 2',
|
||||
category: 'Mietvertrag',
|
||||
size: '1,7 MB',
|
||||
date: '01.06.2024',
|
||||
},
|
||||
]
|
||||
|
||||
export const threads: Thread[] = [
|
||||
{
|
||||
id: 'm-1',
|
||||
unitId: DEMO_UNIT_ID,
|
||||
tenant: DEMO_TENANT,
|
||||
subject: 'Mietkaution – Rückzahlungsnachweis',
|
||||
unreadByAdmin: false,
|
||||
unreadByTenant: true,
|
||||
messages: [
|
||||
{
|
||||
id: 'm-1-a',
|
||||
from: 'tenant',
|
||||
author: DEMO_TENANT,
|
||||
text: 'Guten Tag, könnten Sie mir bitte den aktuellen Stand meiner Mietkaution mit Nachweis der Verzinsung zusenden?',
|
||||
at: '27.09.2026, 10:12',
|
||||
},
|
||||
{
|
||||
id: 'm-1-b',
|
||||
from: 'admin',
|
||||
author: 'Hocks Verwaltung',
|
||||
text: 'Guten Tag Frau Berger, die Kaution wurde mit 1.500,00 € auf dem Treuhandkonto verbucht. Die Verzinsung für 2025 beträgt 18,40 € – den Nachweis finden Sie ab sofort auch unter Dokumente.',
|
||||
at: '29.09.2026, 09:03',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'm-2',
|
||||
unitId: 'rw-9',
|
||||
tenant: units.find((u) => u.id === 'rw-9')?.tenant ?? '',
|
||||
subject: 'Terminabstimmung Wohnungsbegehung (Schimmel)',
|
||||
unreadByAdmin: true,
|
||||
unreadByTenant: false,
|
||||
messages: [
|
||||
{
|
||||
id: 'm-2-a',
|
||||
from: 'tenant',
|
||||
author: units.find((u) => u.id === 'rw-9')?.tenant ?? '',
|
||||
text: 'Aufgrund der Schadensmeldung schlage ich einen Begehungstermin nächste Woche vor. Passt Mittwoch oder Freitag Nachmittag?',
|
||||
at: '01.10.2026, 08:45',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export const announcements: Announcement[] = [
|
||||
{
|
||||
id: 'a-1',
|
||||
title: 'Wasserabschaltung Hauptstraße 12',
|
||||
text: 'Am Donnerstag, 08.10.2026, 09:00–13:00 Uhr findet eine Druckerhöhungs-Pumpen-Wartung statt. In dieser Zeit steht kein Wasser zur Verfügung.',
|
||||
date: '02.10.2026',
|
||||
tag: 'Technik',
|
||||
},
|
||||
{
|
||||
id: 'a-2',
|
||||
title: 'Herbst-Hausbegehung mit Hausmeister',
|
||||
text: 'Am Samstag, 17.10.2026, 10:00 Uhr geht es gemeinsam durch alle Häuser. Anschließend gibt es Kaffee im Hof von Am Park 5.',
|
||||
date: '28.09.2026',
|
||||
tag: 'Termin',
|
||||
},
|
||||
{
|
||||
id: 'a-3',
|
||||
title: 'Tiefgarage Ringweg 3: Reinigung',
|
||||
text: 'Die Tiefgarage wird am 21.10.2026 gereinigt. Bitte Fahrzeuge bis 07:30 Uhr entfernen, sonst erfolgt ein kostenpflichtiges Versetzen.',
|
||||
date: '20.09.2026',
|
||||
tag: 'Hinweis',
|
||||
},
|
||||
{
|
||||
id: 'a-4',
|
||||
title: 'Nebenkostenabrechnungen 2025 versandt',
|
||||
text: 'Alle Abrechnungen liegen digital im Dokumentenbereich vor. Nachzahlungen sind bis 31.10.2026 überwiesen.',
|
||||
date: '31.05.2026',
|
||||
tag: 'Abrechnung',
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user