Add income and result card.
This commit is contained in:
13
package-lock.json
generated
13
package-lock.json
generated
@@ -8,6 +8,7 @@
|
|||||||
"name": "allmende-solimieten",
|
"name": "allmende-solimieten",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@chakra-ui/icons": "^2.1.1",
|
||||||
"@chakra-ui/react": "^2.8.2",
|
"@chakra-ui/react": "^2.8.2",
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.5",
|
"@emotion/styled": "^11.11.5",
|
||||||
@@ -2313,6 +2314,18 @@
|
|||||||
"react": ">=18"
|
"react": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@chakra-ui/icons": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/icons/-/icons-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-3p30hdo4LlRZTT5CwoAJq3G9fHI0wDc0pBaMHj4SUn0yomO+RcDRlzhdXqdr5cVnzax44sqXJVnf3oQG0eI+4g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/icon": "3.2.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@chakra-ui/system": ">=2.0.0",
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@chakra-ui/image": {
|
"node_modules/@chakra-ui/image": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@chakra-ui/image/-/image-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@chakra-ui/image/-/image-2.1.0.tgz",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@chakra-ui/icons": "^2.1.1",
|
||||||
"@chakra-ui/react": "^2.8.2",
|
"@chakra-ui/react": "^2.8.2",
|
||||||
"@emotion/react": "^11.11.4",
|
"@emotion/react": "^11.11.4",
|
||||||
"@emotion/styled": "^11.11.5",
|
"@emotion/styled": "^11.11.5",
|
||||||
|
|||||||
BIN
public/logo.png
Normal file
BIN
public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB |
112
src/App.js
112
src/App.js
@@ -3,7 +3,7 @@ import { React, useState } from 'react';
|
|||||||
import {
|
import {
|
||||||
ChakraProvider,
|
ChakraProvider,
|
||||||
Text,
|
Text,
|
||||||
theme,
|
extendTheme,
|
||||||
Select,
|
Select,
|
||||||
Card,
|
Card,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
@@ -11,11 +11,21 @@ import {
|
|||||||
CardBody,
|
CardBody,
|
||||||
Center,
|
Center,
|
||||||
SimpleGrid,
|
SimpleGrid,
|
||||||
|
Box,
|
||||||
|
Stack,
|
||||||
|
NumberInput,
|
||||||
|
NumberInputField,
|
||||||
|
Slider,
|
||||||
|
SliderFilledTrack,
|
||||||
|
SliderMark,
|
||||||
|
SliderTrack,
|
||||||
|
SliderThumb,
|
||||||
|
Tooltip
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
import { FlatDetails } from './Solimieten';
|
import { FlatDetails, ResultsCard } from './Solimieten';
|
||||||
import { ColorModeSwitcher } from './ColorModeSwitcher';
|
|
||||||
import { flatData } from './Data';
|
import { flatData } from './Data';
|
||||||
|
import { Nav } from './Nav';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
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" }]);
|
||||||
@@ -23,6 +33,28 @@ function App() {
|
|||||||
const [selectedBuilding, setSelectedBuilding] = useState();
|
const [selectedBuilding, setSelectedBuilding] = useState();
|
||||||
const [selectedFlat, setSelectedFlat] = useState();
|
const [selectedFlat, setSelectedFlat] = useState();
|
||||||
|
|
||||||
|
const [income, setIncome] = useState(0);
|
||||||
|
|
||||||
|
const [sliderValue, setSliderValue] = useState(30)
|
||||||
|
const [showTooltip, setShowTooltip] = useState(false)
|
||||||
|
|
||||||
|
const theme = extendTheme({
|
||||||
|
"colors": {
|
||||||
|
"gray": {
|
||||||
|
"50": "#F3FEE7",
|
||||||
|
"100": "#DEFCBB",
|
||||||
|
"200": "#C8FA8F",
|
||||||
|
"300": "#B3F862",
|
||||||
|
"400": "#9DF636",
|
||||||
|
"500": "#88F50A",
|
||||||
|
"600": "#6DC408",
|
||||||
|
"700": "#529306",
|
||||||
|
"800": "#366204",
|
||||||
|
"900": "#1B3102"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function buildingSelected(e) {
|
function buildingSelected(e) {
|
||||||
var newOptions;
|
var newOptions;
|
||||||
if (e.target.value === "south") {
|
if (e.target.value === "south") {
|
||||||
@@ -48,17 +80,26 @@ function App() {
|
|||||||
setSelectedFlat(flatOptions[index]);
|
setSelectedFlat(flatOptions[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const formatEuro = (val) => val + ' €';
|
||||||
|
const parseEuro = (val) => val.replace(/^€/, '')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<ChakraProvider theme={theme}>
|
<ChakraProvider theme={theme}>
|
||||||
|
<Nav></Nav>
|
||||||
<Center>
|
<Center>
|
||||||
<SimpleGrid columns={2} spacing={4}>
|
<SimpleGrid columns={2} spacing={4}>
|
||||||
|
<Heading>Wohnung</Heading>
|
||||||
|
<Box></Box>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<Heading size='md'>Wohnungsauswahl</Heading>
|
<Heading size='md'>Wohnungsauswahl</Heading>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<Text>View a summary of all your customers over the last month.</Text>
|
<Stack spacing={4} w="500px">
|
||||||
<Select placeholder='Gebäude auswählen' onChange={buildingSelected}>
|
<Select placeholder='Gebäude auswählen' onChange={buildingSelected}>
|
||||||
<option value='north'>Nordbau</option>
|
<option value='north'>Nordbau</option>
|
||||||
<option value='south'>Südbau</option>
|
<option value='south'>Südbau</option>
|
||||||
@@ -69,9 +110,72 @@ function App() {
|
|||||||
<Select placeholder='Wohnung auswählen' onChange={flatSelected}>
|
<Select placeholder='Wohnung auswählen' onChange={flatSelected}>
|
||||||
{flatOptions.map((flat, index) => <option value={index} >{flat.print()}</option>)}
|
{flatOptions.map((flat, index) => <option value={index} >{flat.print()}</option>)}
|
||||||
</Select>
|
</Select>
|
||||||
|
</Stack>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
<FlatDetails flat={selectedFlat} />
|
<FlatDetails flat={selectedFlat} />
|
||||||
|
|
||||||
|
<Heading>Selbsteinschätzung</Heading>
|
||||||
|
<Box></Box>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardBody maxW={500}>
|
||||||
|
<Stack spacing={3}>
|
||||||
|
<Text>Wie hoch ist euer/dein Haushaltsnetto? Beachtet dabei alle regelmäßigen Einkünfte wie Gehalt, Rente, Mieteinkünfte oder Kapitalerträge </Text>
|
||||||
|
<NumberInput
|
||||||
|
onChange={(valueString) => setIncome(parseEuro(valueString))}
|
||||||
|
value={formatEuro(income)}
|
||||||
|
>
|
||||||
|
<NumberInputField />
|
||||||
|
</NumberInput>
|
||||||
|
|
||||||
|
<Text>Wie viel Prozent eures/deines Nettoeinkommens kannst du für Miete aufbringen?</Text>
|
||||||
|
<Slider
|
||||||
|
id='slider'
|
||||||
|
defaultValue={30}
|
||||||
|
min={10}
|
||||||
|
max={50}
|
||||||
|
mb={5}
|
||||||
|
colorScheme='teal'
|
||||||
|
onChange={(v) => setSliderValue(v)}
|
||||||
|
onMouseEnter={() => setShowTooltip(true)}
|
||||||
|
onMouseLeave={() => setShowTooltip(false)}
|
||||||
|
>
|
||||||
|
<SliderMark value={10} mt='1' ml='-2.5' fontSize='sm'>
|
||||||
|
10%
|
||||||
|
</SliderMark>
|
||||||
|
<SliderMark value={20} mt='1' ml='-2.5' fontSize='sm'>
|
||||||
|
20%
|
||||||
|
</SliderMark>
|
||||||
|
<SliderMark value={30} mt='1' ml='-2.5' fontSize='sm'>
|
||||||
|
30%
|
||||||
|
</SliderMark>
|
||||||
|
<SliderMark value={40} mt='1' ml='-2.5' fontSize='sm'>
|
||||||
|
40%
|
||||||
|
</SliderMark>
|
||||||
|
<SliderMark value={50} mt='1' ml='-2.5' fontSize='sm'>
|
||||||
|
50%
|
||||||
|
</SliderMark>
|
||||||
|
<SliderTrack>
|
||||||
|
<SliderFilledTrack />
|
||||||
|
</SliderTrack>
|
||||||
|
<Tooltip
|
||||||
|
hasArrow
|
||||||
|
bg='teal.500'
|
||||||
|
color='white'
|
||||||
|
placement='top'
|
||||||
|
isOpen={showTooltip}
|
||||||
|
label={`${sliderValue}%`}
|
||||||
|
>
|
||||||
|
<SliderThumb />
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
|
||||||
|
</Slider>
|
||||||
|
</Stack>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
<ResultsCard income={income} percentage={sliderValue} flat={selectedFlat} />
|
||||||
</SimpleGrid>
|
</SimpleGrid>
|
||||||
</Center>
|
</Center>
|
||||||
</ChakraProvider >
|
</ChakraProvider >
|
||||||
|
|||||||
88
src/Nav.js
Normal file
88
src/Nav.js
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Flex,
|
||||||
|
Avatar,
|
||||||
|
Link,
|
||||||
|
Button,
|
||||||
|
Menu,
|
||||||
|
MenuButton,
|
||||||
|
MenuList,
|
||||||
|
MenuItem,
|
||||||
|
MenuDivider,
|
||||||
|
useDisclosure,
|
||||||
|
useColorModeValue,
|
||||||
|
Stack,
|
||||||
|
useColorMode,
|
||||||
|
Center,
|
||||||
|
Image,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import { MoonIcon, SunIcon } from '@chakra-ui/icons';
|
||||||
|
|
||||||
|
const NavLink = ({ children }) => (
|
||||||
|
<Link
|
||||||
|
px={2}
|
||||||
|
py={1}
|
||||||
|
rounded={'md'}
|
||||||
|
_hover={{
|
||||||
|
textDecoration: 'none',
|
||||||
|
bg: useColorModeValue('gray.200', 'gray.700'),
|
||||||
|
}}
|
||||||
|
href={'#'}>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
|
||||||
|
export function Nav() {
|
||||||
|
const { colorMode, toggleColorMode } = useColorMode();
|
||||||
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box mb="10px" bg={useColorModeValue('gray.100', 'gray.900')} px={4}>
|
||||||
|
<Flex h={16} alignItems={'center'} justifyContent={'space-between'}>
|
||||||
|
<Box><Image src="logo.png" w='120px'></Image></Box>
|
||||||
|
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Stack direction={'row'} spacing={7}>
|
||||||
|
<Button onClick={toggleColorMode}>
|
||||||
|
{colorMode === 'light' ? <MoonIcon /> : <SunIcon />}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{/* <Menu>
|
||||||
|
<MenuButton
|
||||||
|
as={Button}
|
||||||
|
rounded={'full'}
|
||||||
|
variant={'link'}
|
||||||
|
cursor={'pointer'}
|
||||||
|
minW={0}>
|
||||||
|
<Avatar
|
||||||
|
size={'sm'}
|
||||||
|
src={'https://avatars.dicebear.com/api/male/username.svg'}
|
||||||
|
/>
|
||||||
|
</MenuButton>
|
||||||
|
<MenuList alignItems={'center'}>
|
||||||
|
<br />
|
||||||
|
<Center>
|
||||||
|
<Avatar
|
||||||
|
size={'2xl'}
|
||||||
|
src={'https://avatars.dicebear.com/api/male/username.svg'}
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
<br />
|
||||||
|
<Center>
|
||||||
|
<p>Username</p>
|
||||||
|
</Center>
|
||||||
|
<br />
|
||||||
|
<MenuDivider />
|
||||||
|
<MenuItem>Your Servers</MenuItem>
|
||||||
|
<MenuItem>Account Settings</MenuItem>
|
||||||
|
<MenuItem>Logout</MenuItem>
|
||||||
|
</MenuList>
|
||||||
|
</Menu> */}
|
||||||
|
</Stack>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -7,7 +7,13 @@ import {
|
|||||||
StackDivider,
|
StackDivider,
|
||||||
Box,
|
Box,
|
||||||
Text,
|
Text,
|
||||||
Badge
|
Badge,
|
||||||
|
Stat,
|
||||||
|
StatLabel,
|
||||||
|
StatNumber,
|
||||||
|
StatHelpText,
|
||||||
|
StatArrow,
|
||||||
|
StatGroup
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
|
|
||||||
export function FlatDetails({ flat }) {
|
export function FlatDetails({ flat }) {
|
||||||
@@ -71,3 +77,28 @@ export function FlatDetails({ flat }) {
|
|||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ResultsCard({ income, percentage, flat }) {
|
||||||
|
var body = <CardBody></CardBody>
|
||||||
|
if (flat) {
|
||||||
|
var rent = income * percentage / 100;
|
||||||
|
var relativeRent = rent / flat.sizePrivate;
|
||||||
|
body = <CardBody>
|
||||||
|
<StatGroup>
|
||||||
|
<Stat>
|
||||||
|
<StatLabel>Miete</StatLabel>
|
||||||
|
<StatNumber>{rent} €</StatNumber>
|
||||||
|
</Stat>
|
||||||
|
|
||||||
|
<Stat>
|
||||||
|
<StatLabel>Pro m²</StatLabel>
|
||||||
|
<StatNumber>{relativeRent.toFixed(2)} €</StatNumber>
|
||||||
|
</Stat>
|
||||||
|
</StatGroup>
|
||||||
|
</CardBody>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Card>
|
||||||
|
{body}
|
||||||
|
</Card>
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user