Hocks Mieterportal: 5 Module (Dashboard, Mietkonto, Schadensmeldungen, Dokumente, Nachrichten), Docker-Setup, eigenes Branding

This commit is contained in:
2026-10-02 10:02:19 +02:00
commit 38d5099a2c
91 changed files with 17062 additions and 0 deletions
+333
View File
@@ -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',
},
]