Compare commits
10 Commits
49e4da2da8
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 204e5cb660 | |||
|
|
321a11367e | ||
|
|
02d5c5f1ca | ||
|
|
ac8436bcd3 | ||
|
|
ea33a0c95c | ||
|
|
6696575a0e | ||
|
|
540ba03f27 | ||
|
|
7099d6b3e1 | ||
|
|
243ca18eb5 | ||
|
|
4a0f47f03b |
23
prepareFlatData.py
Normal file
23
prepareFlatData.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from pandas import read_excel
|
||||||
|
import json
|
||||||
|
|
||||||
|
PATH = "/home/niklas/ownCloud/wohpro/04_AGs/04_AG_Finanzen/Finanzierungsplan MHS/2025-09-11_FP_Allmende_AG_Treffen.xlsx"
|
||||||
|
|
||||||
|
OUTPUT_PATH = "./rent_data.json"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
df = read_excel(PATH, sheet_name="Solimieten Daten Onlinetool")
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
for index, row in df.iterrows():
|
||||||
|
data[row["Wohneinheit"]] = {
|
||||||
|
"size_private": row["Zahlfläche privat (m²)"],
|
||||||
|
"size_shared": row["Zahlfläche intern"],
|
||||||
|
"min_rent": row["Mindestmiete"],
|
||||||
|
"free_rent": row["Standardmiete frei"],
|
||||||
|
"wbs_rent": row["Standardmiete WBS"],
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(OUTPUT_PATH, "w") as f:
|
||||||
|
json.dump(data, f)
|
||||||
7
pyproject.toml
Normal file
7
pyproject.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[project]
|
||||||
|
name = "allmende_solimieten"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"pandas[excel]",
|
||||||
|
]
|
||||||
|
requires-python = ">=3.12"
|
||||||
40
src/App.js
40
src/App.js
@@ -1,4 +1,4 @@
|
|||||||
import { React, useState } from 'react';
|
import { React, useState, useEffect } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChakraProvider,
|
ChakraProvider,
|
||||||
@@ -12,20 +12,22 @@ import {
|
|||||||
useColorModeValue,
|
useColorModeValue,
|
||||||
OrderedList,
|
OrderedList,
|
||||||
ListItem,
|
ListItem,
|
||||||
|
Alert,
|
||||||
|
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
import { FlatSelectionCard, FlatDetailsCard, SelfEvaluationCard, ResultsCard } from './Solimieten';
|
import { FlatSelectionCard, FlatDetailsCard, SelfEvaluationCard, ResultsCard } from './Solimieten';
|
||||||
|
|
||||||
import { Nav } from './Nav';
|
import { Nav } from './Nav';
|
||||||
|
import { minRent, maxRent, minRentFactor } from './Data';
|
||||||
function App() {
|
function App() {
|
||||||
|
|
||||||
const [selectedFlat, setSelectedFlat] = useState();
|
const [selectedFlat, setSelectedFlat] = useState();
|
||||||
const [selectedRoom, setSelectedRoom] = useState();
|
const [selectedRoom, setSelectedRoom] = useState();
|
||||||
const [numAdults, setNumAdults] = useState(1);
|
|
||||||
|
|
||||||
const [rent, setRent] = useState(0);
|
const [rent, setRent] = useState(0);
|
||||||
|
const [flatRent, setFlatRent] = useState();
|
||||||
|
|
||||||
const theme = extendTheme({
|
const theme = extendTheme({
|
||||||
"colors": {
|
"colors": {
|
||||||
@@ -44,7 +46,30 @@ function App() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setFlatRent(null);
|
||||||
|
if (selectedFlat && (selectedFlat.wgRoomList.length === 0 || selectedRoom)) {
|
||||||
|
console.log("Recalculating Rent...");
|
||||||
|
var commonAreaShare = 60;
|
||||||
|
var kitchenCost = 50;
|
||||||
|
var sizePrivate = selectedFlat.sizePrivate;
|
||||||
|
var internalAreaShare = 0;
|
||||||
|
|
||||||
|
if (selectedFlat.wgRoomList.length > 0) {
|
||||||
|
internalAreaShare = selectedFlat.calcInternalAreaShare(selectedRoom);
|
||||||
|
sizePrivate = selectedRoom.size;
|
||||||
|
kitchenCost = kitchenCost / selectedFlat.wgRoomList.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newRent = {
|
||||||
|
minCovering: (sizePrivate + internalAreaShare) * minRent + kitchenCost + commonAreaShare,
|
||||||
|
maxCovering: (sizePrivate + internalAreaShare) * maxRent + kitchenCost + commonAreaShare
|
||||||
|
}
|
||||||
|
newRent.min = newRent.minCovering * minRentFactor;
|
||||||
|
|
||||||
|
setFlatRent(newRent);
|
||||||
|
}
|
||||||
|
}, [selectedFlat, selectedRoom])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -55,7 +80,7 @@ function App() {
|
|||||||
<Stack maxWidth={1200}>
|
<Stack maxWidth={1200}>
|
||||||
<Box p={6} borderRadius="lg" bg={useColorModeValue('gray.100', 'gray.200')}>
|
<Box p={6} borderRadius="lg" bg={useColorModeValue('gray.100', 'gray.200')}>
|
||||||
<Text>
|
<Text>
|
||||||
<Heading>Allemende Solimieten-Helferlein</Heading>
|
<Heading>Allmende Solimieten-Helferlein</Heading>
|
||||||
|
|
||||||
Im Rahmen des Konzept für solidarische Mieten, kann jede Partei in der Allmende ihre Miethöhe selbst bestimmen.
|
Im Rahmen des Konzept für solidarische Mieten, kann jede Partei in der Allmende ihre Miethöhe selbst bestimmen.
|
||||||
Dieses Tool soll als Orientierungshilfe bei der Selbsteinschätzung dienen.
|
Dieses Tool soll als Orientierungshilfe bei der Selbsteinschätzung dienen.
|
||||||
@@ -69,19 +94,20 @@ function App() {
|
|||||||
<ListItem>Nun siehst du den daraus resultierenden Mietpreis absolut und auf den Quadratmeter gerechnet.</ListItem>
|
<ListItem>Nun siehst du den daraus resultierenden Mietpreis absolut und auf den Quadratmeter gerechnet.</ListItem>
|
||||||
</OrderedList>
|
</OrderedList>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<SimpleGrid pt={5} columns={{ base: 1, md: 2, lg: 2 }} spacing={4}>
|
<SimpleGrid pt={5} columns={{ base: 1, md: 2, lg: 2 }} spacing={4}>
|
||||||
|
|
||||||
<Heading>Wohnung</Heading>
|
<Heading>Wohnung</Heading>
|
||||||
<Box></Box>
|
<Box></Box>
|
||||||
|
|
||||||
<FlatSelectionCard setSelectedFlat={setSelectedFlat} onRoomSelected={setSelectedRoom} onNumAdultsSelected={setNumAdults} />
|
<FlatSelectionCard setSelectedFlat={setSelectedFlat} onRoomSelected={setSelectedRoom} />
|
||||||
<FlatDetailsCard flat={selectedFlat} room={selectedRoom} numAdults={numAdults} />
|
<FlatDetailsCard flat={selectedFlat} room={selectedRoom} flatRent={flatRent} />
|
||||||
|
|
||||||
<Heading>Selbsteinschätzung</Heading>
|
<Heading>Selbsteinschätzung</Heading>
|
||||||
<Box></Box>
|
<Box></Box>
|
||||||
|
|
||||||
<SelfEvaluationCard rent={rent} setRent={setRent} />
|
<SelfEvaluationCard rent={rent} setRent={setRent} />
|
||||||
<ResultsCard rent={rent} flat={selectedFlat} room={selectedRoom} />
|
<ResultsCard rent={rent} flat={selectedFlat} room={selectedRoom} flatRent={flatRent} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</Center>
|
||||||
|
|||||||
90
src/Data.js
90
src/Data.js
@@ -1,8 +1,9 @@
|
|||||||
|
import rentData from './rent_data.json';
|
||||||
class Flat {
|
class Flat {
|
||||||
constructor(name, numRooms, sizePrivate, isWbs = false, isAccessible = false, wgRoomList = null) {
|
constructor(name, numRooms, isWbs = false, isAccessible = false, wgRoomList = null, combineRooms = null) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.numRooms = numRooms;
|
this.numRooms = numRooms;
|
||||||
this.sizePrivate = sizePrivate;
|
this.sizePrivate = 0;
|
||||||
this.isWbs = isWbs;
|
this.isWbs = isWbs;
|
||||||
this.sizeShared = 0;
|
this.sizeShared = 0;
|
||||||
// Normal flats have as many people as rooms
|
// Normal flats have as many people as rooms
|
||||||
@@ -10,11 +11,22 @@ class Flat {
|
|||||||
if (!wgRoomList) {
|
if (!wgRoomList) {
|
||||||
this.wgRoomList = [];
|
this.wgRoomList = [];
|
||||||
this.numPeople = numRooms;
|
this.numPeople = numRooms;
|
||||||
|
var idList = combineRooms ? combineRooms : [name];
|
||||||
|
this.minRent = 0;
|
||||||
|
this.wbsRent = 0;
|
||||||
|
this.freeRent = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < idList.length; i++) {
|
||||||
|
this.minRent += rentData[idList[i]].min_rent;
|
||||||
|
this.wbsRent += rentData[idList[i]].wbs_rent;
|
||||||
|
this.freeRent += rentData[idList[i]].free_rent;
|
||||||
|
this.sizePrivate += rentData[idList[i]].size_private;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.wgRoomList = wgRoomList;
|
this.wgRoomList = wgRoomList;
|
||||||
this.sizeShared = this.sizePrivate;
|
this.sizeShared = this.sizePrivate;
|
||||||
for (var i = 0; i < this.wgRoomList.length; i++) {
|
for (var j = 0; j < this.wgRoomList.length; j++) {
|
||||||
this.sizeShared -= this.wgRoomList[i].size;
|
this.sizeShared -= this.wgRoomList[j].size;
|
||||||
}
|
}
|
||||||
this.numPeople = numRooms - 1;
|
this.numPeople = numRooms - 1;
|
||||||
}
|
}
|
||||||
@@ -45,10 +57,16 @@ class Flat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Room {
|
class Room {
|
||||||
constructor(name, size, numPeople = 1) {
|
constructor(name, numPeople = 1, id = null) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.size = size;
|
|
||||||
this.numPeople = numPeople;
|
this.numPeople = numPeople;
|
||||||
|
|
||||||
|
var key = id ? id : name;
|
||||||
|
this.sizePrivate = rentData[key].size_private;
|
||||||
|
this.sizeShared = rentData[key].size_shared;
|
||||||
|
this.minRent = rentData[key].min_rent;
|
||||||
|
this.freeRent = rentData[key].free_rent;
|
||||||
|
this.wbsRent = rentData[key].wbs_rent;
|
||||||
}
|
}
|
||||||
|
|
||||||
print() {
|
print() {
|
||||||
@@ -59,56 +77,58 @@ class Room {
|
|||||||
export const flatData = {
|
export const flatData = {
|
||||||
"north": {
|
"north": {
|
||||||
0: [
|
0: [
|
||||||
new Flat("W 0.1 (WG)", 4, 84.834, false, false, [
|
new Flat("W 0.1 (WG)", 4, false, false, [
|
||||||
new Room("0.1 02", 12.523), new Room("0.1 03", 12.102), new Room("0.1 04", 14.746)
|
new Room("0.1.02"), new Room("0.1.03"), new Room("0.1.04")
|
||||||
]),
|
]),
|
||||||
new Flat("W 0.2", 2, 53.453, true),
|
new Flat("0.2", 2, true),
|
||||||
new Flat("W 0.3", 3, 63.498, true)
|
new Flat("0.3", 3, true)
|
||||||
],
|
],
|
||||||
1: [
|
1: [
|
||||||
new Flat("W 1.1", 4, 84.794, true),
|
new Flat("1.1", 4, true),
|
||||||
new Flat("W 1.2", 1, 36.469, true),
|
new Flat("1.2", 1, true),
|
||||||
new Flat("W 1.3 (WG)", 4, 63.128, true, false, [
|
new Flat("W 1.3 (WG)", 4, true, false, [
|
||||||
new Room("1.3 02", 11.434), new Room("1.3 03", 11.245), new Room("1.3 04", 11.77)
|
new Room("1.3.02"), new Room("1.3.03"), new Room("1.3.04")
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
2: [
|
2: [
|
||||||
new Flat("W 2.1", 4, 84.794, true),
|
new Flat("2.1", 4, true),
|
||||||
new Flat("W 2.2", 2, 46.261, true),
|
new Flat("2.2", 2, true),
|
||||||
new Flat("W 2.3 (Cluster)", 5, 154.196, true, true, [
|
new Flat("W 2.3 (Cluster)", 5, true, true, [
|
||||||
new Room("1 Person", 28.774), new Room("2 Personen", 46.32, 2), new Room("1 Person (rollstuhlgerecht)", 41.814)
|
new Room("1 Person", 1, "2.3.02"), new Room("2 Personen", 2, "2.3.05"), new Room("1 Person (rollstuhlgerecht)", 1, "2.3.09")
|
||||||
]),
|
]),
|
||||||
new Flat("W 2.4", 2, 64.265, true, true)
|
new Flat("2.4", 2, true, true)
|
||||||
],
|
],
|
||||||
3: [
|
3: [
|
||||||
new Flat("W 3.1", 4, 84.794),
|
new Flat("3.1", 4),
|
||||||
new Flat("W 3.2 (Cluster)", 5, 154.97, true, true, [
|
new Flat("W 3.2 (Cluster)", 5, true, true, [
|
||||||
new Room("1 Person", 28.531), new Room("2 Personen", 47.146, 2), new Room("1 Person (rollstuhlgerecht)", 44.036)
|
new Room("1 Person", 1, "3.2.02"), new Room("2 Personen", 2, "3.2.05"), new Room("1 Person (rollstuhlgerecht)", 1, "3.2.09")
|
||||||
]),
|
]),
|
||||||
new Flat("W 3.3", 3, 63.128, true)
|
new Flat("3.3", 3, true)
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"south": {
|
"south": {
|
||||||
0: [
|
0: [
|
||||||
new Flat("W 0.4", 2, 54.905, true),
|
new Flat("0.4", 2, true),
|
||||||
new Flat("W 0.5", 4, 83.416, true),
|
new Flat("0.5", 4, true),
|
||||||
new Flat("W 0.6", 5, 107.733, true),
|
new Flat("0.6", 5, true),
|
||||||
],
|
],
|
||||||
1: [
|
1: [
|
||||||
new Flat("W 1.4", 2, 59.442),
|
new Flat("1.4", 2),
|
||||||
new Flat("W 1.5 (WG)", 5, 89.209, true, false,
|
new Flat("W 1.5 (WG)", 5, true, false,
|
||||||
[new Room("1.5 02", 15.448), new Room("1.5 05", 11.489), new Room("1.5 06", 13.462)]
|
[new Room("1.5.02"), new Room("1.5.03"), new Room("1.5.05"), new Room("1.5.06")]
|
||||||
),
|
),
|
||||||
new Flat("W 1.6.0", 1, 30.431),
|
new Flat("1.6.2", 1),
|
||||||
new Flat("W 1.6", 5, 108.761),
|
new Flat("1.6.1", 5),
|
||||||
],
|
],
|
||||||
2: [
|
2: [
|
||||||
new Flat("W 2.5", 2, 58.882),
|
new Flat("2.5", 2, true),
|
||||||
new Flat("W 2.6", 4, 89.853, true),
|
new Flat("2.6", 4, true),
|
||||||
new Flat("W 2.7", 5, 101.533)
|
new Flat("2.7", 5)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const addedCost = 1.2;
|
const addedCost = 1.5;
|
||||||
export const minRent = 9.45 + addedCost;
|
export const minRent = 9.45 + addedCost;
|
||||||
export const maxRent = 13.06 + addedCost;
|
export const maxRent = 13.06 + addedCost;
|
||||||
|
|
||||||
|
export const minRentFactor = 0.85;
|
||||||
@@ -14,7 +14,6 @@ import {
|
|||||||
StatNumber,
|
StatNumber,
|
||||||
StatGroup,
|
StatGroup,
|
||||||
Select,
|
Select,
|
||||||
Progress,
|
|
||||||
NumberInput,
|
NumberInput,
|
||||||
NumberInputField,
|
NumberInputField,
|
||||||
Slider,
|
Slider,
|
||||||
@@ -22,12 +21,14 @@ import {
|
|||||||
SliderMark,
|
SliderMark,
|
||||||
SliderTrack,
|
SliderTrack,
|
||||||
SliderThumb,
|
SliderThumb,
|
||||||
Tooltip
|
Tooltip,
|
||||||
|
Alert,
|
||||||
|
AlertIcon
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
import { flatData, minRent, maxRent } from './Data';
|
import { flatData } from './Data';
|
||||||
|
|
||||||
export function FlatSelectionCard({ setSelectedFlat, onRoomSelected, onNumAdultsSelected }) {
|
export function FlatSelectionCard({ setSelectedFlat, onRoomSelected }) {
|
||||||
const [levelOptions, setLevelOption] = useState([{ value: 0, label: "EG" }, { value: 1, label: "1. OG" }, { value: 2, label: "2. OG" }, { value: 3, label: "3. OG" }]);
|
const [levelOptions, setLevelOption] = useState([{ value: 0, label: "EG" }, { value: 1, label: "1. OG" }, { value: 2, label: "2. OG" }, { value: 3, label: "3. OG" }]);
|
||||||
const [flatOptions, setFlatOptions] = useState([]);
|
const [flatOptions, setFlatOptions] = useState([]);
|
||||||
const [roomOptions, setRoomOptions] = useState([]);
|
const [roomOptions, setRoomOptions] = useState([]);
|
||||||
@@ -68,9 +69,6 @@ export function FlatSelectionCard({ setSelectedFlat, onRoomSelected, onNumAdults
|
|||||||
onRoomSelected(roomOptions[e.target.value]);
|
onRoomSelected(roomOptions[e.target.value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function numAdultsSelected(e) {
|
|
||||||
onNumAdultsSelected(e.target.value);
|
|
||||||
}
|
|
||||||
return <Card>
|
return <Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<Heading size='md'>Wohnungsauswahl</Heading>
|
<Heading size='md'>Wohnungsauswahl</Heading>
|
||||||
@@ -88,47 +86,41 @@ export function FlatSelectionCard({ setSelectedFlat, onRoomSelected, onNumAdults
|
|||||||
{flatOptions.map((flat, index) => <option value={index} >{flat.print()}</option>)}
|
{flatOptions.map((flat, index) => <option value={index} >{flat.print()}</option>)}
|
||||||
</Select>
|
</Select>
|
||||||
{roomOptions.length > 0 ? (<Select placeholder='Zimmer auswählen' onChange={roomSelected}>
|
{roomOptions.length > 0 ? (<Select placeholder='Zimmer auswählen' onChange={roomSelected}>
|
||||||
{roomOptions.map((room, index) => <option value={index} >{room.print()} ({room.size} m²)</option>)}
|
{roomOptions.map((room, index) => <option value={index} >{room.print()} ({room.sizePrivate.toFixed(2)} m²)</option>)}
|
||||||
</Select>) : null}
|
</Select>) : null}
|
||||||
<Select placeholder='Anzahl Erwachsene' onChange={numAdultsSelected}>
|
|
||||||
<option value="1">1 erwachsene Person</option>
|
|
||||||
<option value="2">2 erwachsene Personen</option>
|
|
||||||
</Select>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card >
|
</Card >
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FlatDetailsCard({ flat, room, numAdults }) {
|
export function FlatDetailsCard({ flat, room, flatRent }) {
|
||||||
var body = <CardBody>
|
var body = <CardBody>
|
||||||
Bitte auswählen
|
Bitte auswählen
|
||||||
</CardBody>;
|
</CardBody>;
|
||||||
|
|
||||||
var badges = "";
|
var badges = "";
|
||||||
var kitchenCost = 50;
|
|
||||||
var commonAreaShare = 60 * numAdults;
|
|
||||||
|
|
||||||
if (flat && (room || flat.wgRoomList.length === 0)) {
|
if (flat && (flat.wgRoomList.length === 0 || room) && flatRent) {
|
||||||
var sizePrivate = flat.sizePrivate;
|
var freeRent = flat.freeRent;
|
||||||
|
var wbsRent = flat.wbsRent;
|
||||||
|
var minRent = flat.minRent;
|
||||||
if (room) {
|
if (room) {
|
||||||
sizePrivate = room.size;
|
freeRent = room.freeRent;
|
||||||
kitchenCost = kitchenCost / flat.wgRoomList.length;
|
wbsRent = room.wbsRent;
|
||||||
|
minRent = room.minRent;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sizeSharedBox = null;
|
var sizeSharedBox = null;
|
||||||
|
|
||||||
var internalAreaShare = flat.calcInternalAreaShare(room);
|
|
||||||
var totalSizeToPay = flat.calcTotalPayedArea(room);
|
|
||||||
|
|
||||||
if (flat.wgRoomList.length > 0) {
|
if (flat.wgRoomList.length > 0) {
|
||||||
|
var totalSizeToPay = room.sizePrivate + room.sizeShared;
|
||||||
sizeSharedBox = [
|
sizeSharedBox = [
|
||||||
<Box>
|
<Box>
|
||||||
<Heading size='xs' textTransform='uppercase'>
|
<Heading size='xs' textTransform='uppercase'>
|
||||||
Anteil Interne Gemeinschaftsfläche (WG und Cluster)
|
Anteil Interne Gemeinschaftsfläche (WG und Cluster)
|
||||||
</Heading>
|
</Heading>
|
||||||
<Text pt='2' fontSize='sm'>
|
<Text pt='2' fontSize='sm'>
|
||||||
{internalAreaShare.toFixed(2)} m²
|
{room.sizeShared.toFixed(2)} m²
|
||||||
</Text>
|
</Text>
|
||||||
</Box >,
|
</Box >,
|
||||||
<Box>
|
<Box>
|
||||||
@@ -136,7 +128,7 @@ export function FlatDetailsCard({ flat, room, numAdults }) {
|
|||||||
Zahlfläche
|
Zahlfläche
|
||||||
</Heading>
|
</Heading>
|
||||||
<Text pt='2' fontSize='sm'>
|
<Text pt='2' fontSize='sm'>
|
||||||
{sizePrivate.toFixed(2)} m² + {internalAreaShare.toFixed(2)} m² (WG/Cluster-Fläche)
|
{room.sizePrivate.toFixed(2)} m² + {room.sizeShared.toFixed(2)} m² (WG/Cluster-Fläche)
|
||||||
</Text>
|
</Text>
|
||||||
<Text pt={3} size='s' fontWeight='bold'>Gesamt: {totalSizeToPay.toFixed(2)} m² </Text>
|
<Text pt={3} size='s' fontWeight='bold'>Gesamt: {totalSizeToPay.toFixed(2)} m² </Text>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -158,38 +150,39 @@ export function FlatDetailsCard({ flat, room, numAdults }) {
|
|||||||
</Box>
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Heading size='xs' textTransform='uppercase'>
|
<Heading size='xs' textTransform='uppercase'>
|
||||||
Zimmeranzahl und Gesamtfläche
|
Zimmeranzahl {room ? "" : "und Gesamtfläche"}
|
||||||
</Heading>
|
</Heading>
|
||||||
<Text pt='2' fontSize='sm'>
|
<Text pt='2' fontSize='sm'>
|
||||||
{flat.numRooms} Zimmer, {flat.sizePrivate.toFixed(2)} m²
|
{flat.numRooms} Zimmer {room ? "" : " " + flat.sizePrivate.toFixed(2) + "m²"}
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
{sizeSharedBox}
|
{sizeSharedBox}
|
||||||
|
<Box>
|
||||||
|
<Heading size='xs' textTransform='uppercase'>
|
||||||
|
Standardmiete WBS
|
||||||
|
</Heading>
|
||||||
|
<Text fontSize="xs">Die Standardmiete ergibt sich aus dem WBS Satz für die private Fläche, den Betriebskosten, der Küchen-Nutzungspauschale, den Abschlägen für Strom und Wasser sowie einem Gemeinschaftsflächenbeitrag und wird WBS-Wohnungen/Zimmern automatisch zugewiesen, sollte die entsprechende Partei kein Gebot abgeben. <b>Mit der Standardmiete wäre das gesamte Haus finanziert, wenn wir keine Bieterunden durchführen würden.</b></Text>
|
||||||
|
<Text pt='2' fontSize='xl' fontWeight='bold'>
|
||||||
|
{(wbsRent).toFixed(2)} €
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Heading size='xs' textTransform='uppercase'>
|
||||||
|
Standardmiete freifinanziert {flat.isWbs ? "(zum Vergleich)" : ""}
|
||||||
|
</Heading>
|
||||||
|
<Text fontSize="xs">Die Standardmiete freifinanziert, wird analog zur Standardmiete WBS berechnet, wobei der Flächenpreis für freifinanzierte Wohnungen genommen wird. Sie wird frei finanzierten Wohnungen/Zimmern automatisch zugewiesen, sollte die entsprechende Partei kein Gebot abgeben. <b>Mit der Standardmiete wäre das gesamte Haus finanziert, wenn wir keine Bieterunden durchführen würden.</b></Text>
|
||||||
|
<Text pt='2' fontSize='xl' fontWeight='bold'>
|
||||||
|
{(freeRent).toFixed(2)} €
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
<Box>
|
<Box>
|
||||||
<Heading size='xs' textTransform='uppercase'>
|
<Heading size='xs' textTransform='uppercase'>
|
||||||
Mindestmiete
|
Mindestmiete
|
||||||
</Heading>
|
</Heading>
|
||||||
<Text fontSize="xs">Die Mindestmiete ergibt sich aus dem WBS Satz für die private Fläche (9,45 €/m²), den Nebenkosten (1,20 €/m²) und der Küchen-Nutzungspauschale von 50€ pro Küche (in Clustern und WGs auf Parteien aufgeteilt)</Text>
|
<Text fontSize="xs">Die Mindestmiete stellt die untere Grenze dar, die für diese Wohnung geboten werden darf und berechnet sich aus der Standardmiete WBS - 15 %
|
||||||
<Text pt='2' fontSize='xl' fontWeight='bold'>
|
|
||||||
{((sizePrivate + internalAreaShare) * minRent + kitchenCost).toFixed(2)} €
|
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Heading size='xs' textTransform='uppercase'>
|
|
||||||
Deckungsmiete WBS
|
|
||||||
</Heading>
|
|
||||||
<Text fontSize="xs">Die Deckungsmiete beinhaltet einen Beitrag von 60 € pro erwachsener Person für die Gemeinschaftsflächen</Text>
|
|
||||||
<Text pt='2' fontSize='xl' fontWeight='bold'>
|
<Text pt='2' fontSize='xl' fontWeight='bold'>
|
||||||
{((sizePrivate + internalAreaShare) * minRent + kitchenCost + commonAreaShare).toFixed(2)} €
|
{(minRent).toFixed(2)} €
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
<Box>
|
|
||||||
<Heading size='xs' textTransform='uppercase'>
|
|
||||||
Deckungsmiete freifinanziert {flat.isWbs ? "(zum Vergleich)" : ""}
|
|
||||||
</Heading>
|
|
||||||
<Text fontSize="xs">Das ist die Miete, die für diese Wohnung ohne solidarischen Ausgleich anfallen würde{flat.isWbs ? ", wenn Sie frei finanziert wäre " : " "}und ergibt sich aus 13,06 €/m² plus 1,20 €/m² Nebenkosten und Gemeinschaftsflächen-Pauschale.</Text>
|
|
||||||
<Text pt='2' fontSize='xl' fontWeight='bold'>
|
|
||||||
{((sizePrivate + internalAreaShare) * maxRent + kitchenCost + commonAreaShare).toFixed(2)} €
|
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -223,7 +216,7 @@ export function SelfEvaluationCard({ rent, setRent }) {
|
|||||||
const [sliderValue, setSliderValue] = useState(30)
|
const [sliderValue, setSliderValue] = useState(30)
|
||||||
const [showTooltip, setShowTooltip] = useState(false)
|
const [showTooltip, setShowTooltip] = useState(false)
|
||||||
|
|
||||||
const [income, setIncome] = useState(1000)
|
const [income, setIncome] = useState(0)
|
||||||
|
|
||||||
const formatEuro = (val) => val + ' €';
|
const formatEuro = (val) => val + ' €';
|
||||||
const parseEuro = (val) => val.replace(/^€/, '')
|
const parseEuro = (val) => val.replace(/^€/, '')
|
||||||
@@ -298,23 +291,43 @@ export function SelfEvaluationCard({ rent, setRent }) {
|
|||||||
</Card>
|
</Card>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ResultsCard({ rent, flat, room }) {
|
export function ResultsCard({ rent, flat, room, flatRent }) {
|
||||||
var body = <CardBody></CardBody>
|
var body = <CardBody></CardBody>
|
||||||
if (flat && (room || flat.wgRoomList.length === 0)) {
|
if (rent && flat && (room || flat.wgRoomList.length === 0) && flatRent) {
|
||||||
|
var _wbsRent = flat.wbsRent;
|
||||||
|
var _freeRent = flat.freeRent;
|
||||||
|
var _minRent = flat.minRent;
|
||||||
|
if (room) {
|
||||||
|
_wbsRent = room.wbsRent;
|
||||||
|
_freeRent = room.freeRent;
|
||||||
|
_minRent = room.minRent;
|
||||||
|
}
|
||||||
var totalSize = flat.calcTotalPayedArea(room)
|
var totalSize = flat.calcTotalPayedArea(room)
|
||||||
|
var relativeRent = (rent) / totalSize;
|
||||||
|
|
||||||
|
var status = "error", text = "Dieses Gebot läge unter der Mindestmiete und ist nicht zulässig";
|
||||||
|
|
||||||
|
if (rent >= _minRent) {
|
||||||
|
status = 'info';
|
||||||
|
text = "Über der Mindestmiete. "
|
||||||
|
}
|
||||||
|
if (rent >= _wbsRent) {
|
||||||
|
status = 'success';
|
||||||
|
text = 'Über der Standardmiete WBS 🎉'
|
||||||
|
}
|
||||||
|
if (rent >= _freeRent) {
|
||||||
|
status = 'success';
|
||||||
|
text = 'Über der Standardmiete freifinanziert 🎉🎉🎉'
|
||||||
|
}
|
||||||
|
|
||||||
var relativeRent = rent / totalSize;
|
|
||||||
var rangePosition = ((relativeRent - minRent) / (maxRent - minRent)) * 100;
|
|
||||||
if (rangePosition < 0) { rangePosition = 0; }
|
|
||||||
if (rangePosition > 100) { rangePosition = 100; }
|
|
||||||
var color = "green";
|
|
||||||
if (rangePosition > 33) { color = "yellow"; }
|
|
||||||
if (rangePosition > 66) { color = "red"; }
|
|
||||||
body = <CardBody>
|
body = <CardBody>
|
||||||
<Stack>
|
<Stack>
|
||||||
|
<Text fontWeight="bold">
|
||||||
|
Das ergäbe eine Miete von:
|
||||||
|
</Text>
|
||||||
<StatGroup>
|
<StatGroup>
|
||||||
<Stat>
|
<Stat>
|
||||||
<StatLabel>Miete</StatLabel>
|
<StatLabel>Warmmiete</StatLabel>
|
||||||
<StatNumber>{rent} €</StatNumber>
|
<StatNumber>{rent} €</StatNumber>
|
||||||
</Stat>
|
</Stat>
|
||||||
|
|
||||||
@@ -323,22 +336,10 @@ export function ResultsCard({ rent, flat, room }) {
|
|||||||
<StatNumber>{relativeRent.toFixed(2)} € </StatNumber>
|
<StatNumber>{relativeRent.toFixed(2)} € </StatNumber>
|
||||||
</Stat>
|
</Stat>
|
||||||
</StatGroup>
|
</StatGroup>
|
||||||
<Text>
|
<Alert status={status}>
|
||||||
Im Folgenden siehst du, wo deine Miete auf der Spanne zwischen WBS-Satz und
|
<AlertIcon />
|
||||||
frei finanzierten Wohnungen ohne Soli-Ausgleich liegen würde.
|
{text}
|
||||||
</Text>
|
</Alert>
|
||||||
<Progress colorScheme={color} size='sm' value={rangePosition} />
|
|
||||||
<StatGroup>
|
|
||||||
<Stat>
|
|
||||||
<StatLabel>WBS Miete</StatLabel>
|
|
||||||
<StatNumber>{minRent.toFixed(2)} €</StatNumber>
|
|
||||||
</Stat>
|
|
||||||
|
|
||||||
<Stat>
|
|
||||||
<StatLabel>Max</StatLabel>
|
|
||||||
<StatNumber>{maxRent.toFixed(2)} € </StatNumber>
|
|
||||||
</Stat>
|
|
||||||
</StatGroup>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</CardBody>;
|
</CardBody>;
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/rent_data.json
Normal file
1
src/rent_data.json
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user