Bladeren bron

React finalisiert

Leonard Schulz (Arbeit) 2 jaren geleden
bovenliggende
commit
d377f94cce

+ 1 - 1
backend_nodejs/wbs_rechner_express.js

@@ -102,7 +102,7 @@ app.post('/calculate', (req, res) => {
      */
     let totalIncome = 0;
     const persons = req.body;
-    console.log(req.body)
+    console.log(req.body);
     for (const person of persons) {
         for (const income of person.incomes) {
             let annualIncome = income.amount * income.frequency;

+ 4 - 2
fontend_angular/wbs-rechner-angular/src/styles.css

@@ -4,8 +4,8 @@
 :root {
   --background-color: white;
   --main-color: black;
-  --highlight-color: #49a1f8;
-  --light-highlight-color: #9bc9f1;
+  --highlight-color: hsl(214, 56%, 61%);
+  --light-highlight-color: #d6d6d6;
 }
 
 input, select {
@@ -21,6 +21,8 @@ body {
   font-family: "Roboto", sans-serif;
   font-weight: 400;
   font-style: normal;
+  max-width:710px;
+  margin: auto;
 }
 
 h2 {

+ 5 - 2
frontend_react/wbs-rechner-react/src/App.css

@@ -4,8 +4,9 @@
 :root {
   --background-color: white;
   --main-color: black;
-  --highlight-color: #49a1f8;
-  --light-highlight-color: #9bc9f1;
+  --highlight-color: hsl(214, 56%, 61%);
+  --light-highlight-color: #d6d6d6;
+
 }
 
 input, select {
@@ -21,6 +22,8 @@ body {
   font-family: "Roboto", sans-serif;
   font-weight: 400;
   font-style: normal;
+  max-width:710px;
+  margin: auto;
 }
 
 h2 {

+ 229 - 17
frontend_react/wbs-rechner-react/src/App.tsx

@@ -1,34 +1,63 @@
 import React, { ChangeEvent } from "react";
 import "./App.css";
 import Headerbox from "./components/Headerbox";
-
-import { Income } from './interfaces/incomes';
 import { Person } from './interfaces/persons';
+import { Frequency } from "./interfaces/frequency";
+import { Type } from "./interfaces/type";
+import { WBS } from "./interfaces/wbs";
+
+
+import { WbsService } from "./service/wbsService";
 
 
 interface AppState {
-  personanzahl : number;
+  personanzahl: number;
   persons: Person[];
+  wbs: WBS;
+  wbsResult: boolean;
 }
 
+const wbsService = new WbsService();
+
+
 class App extends React.Component<{}, AppState> {
+  types: Array<Type> = [];
+  freq: Array<Frequency> = [];
+
   constructor(props: {}) {
     super(props);
     this.state = {
+      wbsResult: false,
+      wbs: { wbsGranted: "Keinen", difference: 0, percent: 0, yearlyAmount: 0, yearlyAmountMax: 0 },
       personanzahl: 1,
-      persons: [{index: 1, incomes: [], totalincome: 0}]
+      persons: [{ index: 1, incomes: [], totalincome: 0 }]
     };
+
+    wbsService.getTypes().then(types => {
+      types.forEach(type => {
+        this.types.push(type);
+      });
+    });
+
+    wbsService.getFrequencies().then(freqs => {
+      freqs.forEach(freq => {
+        this.freq.push(freq);
+      });
+    });
   }
 
+
+
+
   render() {
     return (
-      <div className="App">
-        <h1>WBS Rechner</h1>
+      <div className="App" id="div_app">
+        <h1 id="ueberschrift">WBS Rechner</h1>
         <Headerbox title="Haushaltsmitglieder">
           <div className="label-container">
             <label htmlFor="personenanzahl">Anzahl Personen im Haushalt</label>
             <input
-              value={this.state.personanzahl}
+              defaultValue={this.state.personanzahl}
               id="personenanzahl"
               type="number"
               min="1"
@@ -37,36 +66,186 @@ class App extends React.Component<{}, AppState> {
             />
           </div>
         </Headerbox>
-        {this.state.persons.map( p =>
+        {this.state.persons.map(p =>
           <Headerbox title={'Daten der ' + p.index + '. Person'}>
-            <div></div>
+            <div>
+              {this.state.persons[p.index - 1].incomes.map(i =>
+                <div className="label_box">
+                  <div className="label-container">
+                    <label htmlFor={'type' + p.index + '_' + i.index}>Typ</label>
+                    <select id={'type_' + p.index + '_' + i.index} defaultValue={i.type} onChange={this.updateIncomeSelectValue}>
+                      <option id={'type_' + p.index + '_' + i.index + '_0'} value={0} disabled>keine Auswahl</option>
+                      {this.types.map(t =>
+                        <option id={'type' + p.index + '_' + i.index + '_' + t.value} value={t.value}> {t.description}</option>
+                      )}
+                    </select>
+
+                  </div>
+                  <div className="label-container">
+                    <label htmlFor={'frequency' + p.index + '_' + i.index}>Frequenz</label>
+                    <select id={'frequency_' + p.index + '_' + i.index} onChange={this.updateIncomeSelectValue} defaultValue={i.frequency} >
+                      <option id={'frequency_' + p.index + '_' + i.index + '_0'} value={0} disabled>keine Auswahl</option>
+                      {this.freq.map(f =>
+                        <option id={'frequency_' + p.index + '_' + i.index + '_' + f.value} value={f.value}> {f.description}</option>
+                      )}
+                    </select>
+                  </div>
+                  <div className="label-container">
+                    <label htmlFor={'amount_' + p.index + '_' + i.index}>Brutto Betrag</label>
+                    <input id={'amount_' + p.index + '_' + i.index} type="number" defaultValue={i.amount} onChange={this.updateIncomeValue} min={0} />
+                  </div>
+                  <div className="label-container">
+                    <label htmlFor={'advertisingCosts_' + p.index + '_' + i.index}>jährliche Werbungskosten</label>
+                    <input id={'advertisingCosts_' + p.index + '_' + i.index} type="number" defaultValue={i.advertisingCosts} onChange={this.updateIncomeValue} min={0} />
+                  </div>
+                  <div className="label-container">
+                    <label htmlFor={'delete_' + p.index + '_' + i.index}>Löschen</label>
+                    <a className="delete-button button"  id={'delete_' + p.index + '_' + i.index} onClick={() => this.deleteIncome(p.index, i.index)}  title={ i.index + ' Einkommen der ' + p.index + ' Person löschen'} >&times;</a>
+                  </div>
+                </div>
+              )}
+              <button onClick={() => this.addIncome(p.index)} className="calculateButton">Einkommen hinzufügen</button>
+            </div>
           </Headerbox>
-        )}
-      </div>
+        )
+        }
+
+        <Headerbox title="WBS berechnen">
+          <h2>Zusammenfassung Haushalt</h2>
+          {this.state.persons.map(p =>
+            <div className="label_box">
+              <div className='label-container'>
+                <label htmlFor={"nr" + p.index}>Nr.</label>
+                <span id={"nr" + p.index}>{p.index}</span>
+              </div>
+
+              <div className="label-container">
+                <label htmlFor={"kindsalter" + p.index}>Kindsalter</label>
+                <span id={"kindsalter" + p.index}>N/A</span>
+              </div>
+
+              <div className="label-container">
+                <label htmlFor={"freibetrage" + p.index}>Freibeträge</label>
+                <span id={"freibetrage" + p.index}>N/A</span>
+              </div>
+
+              <div className="label-container">
+                <label htmlFor={"gesamteinkommen" + p.index}>Gesamteinkommen</label>
+                <span id={"gesamteinkommen" + p.index}>{p.totalincome}</span>
+              </div>
+            </div>
+          )}
+
+          <button onClick={this.calculateWBS.bind(this)} className="calculateButton">WBS berechnen</button>
+
+          {this.state.wbsResult ?
+            <div>
+              <div className="label-container">
+                <label htmlFor="yearlyAmount">anrechenbares jährliches Gesamteinkommen:</label>
+                <span id="yearlyAmount">{this.state.wbs.yearlyAmount} €</span>
+              </div>
+              <div className="label-container">
+                <label htmlFor="yearlyAmountMax">Einkommensgrenze:</label>
+                <span id="yearlyAmountMax">{this.state.wbs.yearlyAmountMax} €</span>
+              </div>
+              <div className="label-container">
+                <label htmlFor="difference">{this.state.wbs.difference > 0 ? 'Überschreitung' : 'Unterschreitung'}</label>
+                <span id="difference">{this.state.wbs.difference} €</span>
+              </div>
+              <div className="label-container">
+                <label htmlFor="percent">Verhältnis Gesamteinkommen / Einkommensgrenze</label>
+                <span id="percent">{this.state.wbs.percent} %</span>
+              </div>
+              <div className="label-container">
+                <label htmlFor="percent">Möglicher WBS:</label>
+                <span id="percent">{this.state.wbs.wbsGranted}</span>
+              </div>
+            </div>
+            :
+            <div></div>
+          }
+
+
+        </Headerbox>
+      </div >
     );
   }
 
-  updateInputValue = (evt :  ChangeEvent<HTMLInputElement>) => {
+  updateInputValue = (evt: ChangeEvent<HTMLInputElement>) => {
     this.setState({ personanzahl: evt.target.valueAsNumber });
     this.refreshPeople(evt.target.valueAsNumber);
   }
 
-  refreshPeople(personenanzahl: number ) {
+  updateIncomeValue = (evt: ChangeEvent<HTMLInputElement>) => {
+    this.updateValueState(evt.target.id, evt.target.valueAsNumber);
+  }
+
+  updateIncomeSelectValue = (evt: ChangeEvent<HTMLSelectElement>) => {
+    this.updateValueState(evt.target.id, evt.target.value);
+  }
+
+
+  updateValueState(id: string, value: any) {
+    var parts = id.split("_");
+    var field = parts[0];
+    var personid: number = parseInt(parts[1]);
+    var incomeId: number = parseInt(parts[2]);
+
+    this.setState(prevState => {
+      const persons = [...prevState.persons];
+      const person = persons[personid - 1];
+      const income = person.incomes[incomeId - 1];
+      if (field === "amount") {
+        income.amount = value;
+        person.totalincome = this.calculateTotalIncome(personid - 1);
+      } else if (field === "advertisingCosts") {
+        income.advertisingCosts = value;
+        person.totalincome = this.calculateTotalIncome(personid - 1);
+      } else if (field === "frequency") {
+        income.frequency = value;
+        person.totalincome = this.calculateTotalIncome(personid - 1);
+      } else if (field === "type") {
+        income.type = value;
+      }
+
+      return { persons };
+    });
+  }
+
+
+  calculateWBS() {
+    var persons: Array<Person> = this.state.persons;
+    wbsService.calculateWbs(persons).then(wbsErg => {
+      this.setState({ wbsResult: true });
+      this.setState({ wbs: wbsErg });
+    });
+  }
+
+
+  calculateTotalIncome(personindex: number): number {
+    let totalIncome = 0;
+    for (const income of this.state.persons[personindex].incomes) {
+      totalIncome += ((income.frequency * income.amount) - income.advertisingCosts);
+    }
+    return totalIncome;
+  }
+
+  refreshPeople(personenanzahl: number) {
     if (personenanzahl > this.state.persons.length) {
       let anzahl = personenanzahl - this.state.persons.length;
       for (let i = 1; i <= anzahl; i++) {
         this.addPerson();
       }
-    } 
+    }
 
     if (personenanzahl < this.state.persons.length) {
       let anzahl = this.state.persons.length - personenanzahl;
       for (let i = 1; i <= anzahl; i++) {
         this.deletePerson(this.state.persons.length);
       }
-    } 
+    }
   }
-  
+
   addPerson() {
     const newPerson: Person = {
       index: this.getHighestIndex(this.state.persons) + 1,
@@ -84,8 +263,41 @@ class App extends React.Component<{}, AppState> {
     }));
   }
 
-  getHighestIndex(arr: Person[]) {
+  deleteIncome = (pindex:number, iindex: number) => {
+    this.setState(prevState => {
+      const persons = [...prevState.persons];
+      const person = persons[pindex];
+      person.incomes = person.incomes.filter(income => income.index !== iindex);
+      return { persons };
+    });
+  }
+
+
+  addIncome(index: number) {
+    const newincome = {
+      index: this.getHighestIndex(this.state.persons[index - 1].incomes) + 1,
+      amount: 0,
+      frequency: 0,
+      advertisingCosts: 0,
+      type: 0
+    };
+    this.setState(prevState => {
+      const persons = [...prevState.persons];
+      const person = persons[index - 1];
+      const isNewIncomeExist = person.incomes.find(income => income.index === newincome.index);
+      if (!isNewIncomeExist) {
+        person.incomes = [...person.incomes, newincome];
+      }
+      return { persons };
+    });
+  }
+
+
+  getHighestIndex(arr: any[]) {
     let highestIndex = 0;
+    if (typeof arr === "undefined") {
+      return highestIndex;
+    }
     for (const item of arr) {
       if (item.index > highestIndex) {
         highestIndex = item.index;

+ 0 - 0
frontend_react/wbs-rechner-react/src/components/Income.css


+ 0 - 12
frontend_react/wbs-rechner-react/src/components/Income.tsx

@@ -1,12 +0,0 @@
-import "./Income.css";
-import React from "react";
-import Headerbox from "./Headerbox.js";
-
-class Income extends React.Component {
-  render() {
-
-    return ("");
-  }
-}
-
-export default Headerbox;

+ 4 - 0
frontend_react/wbs-rechner-react/src/interfaces/frequency.ts

@@ -0,0 +1,4 @@
+export interface Frequency {
+    value: number,
+    description: string
+}

+ 4 - 0
frontend_react/wbs-rechner-react/src/interfaces/type.ts

@@ -0,0 +1,4 @@
+export interface Type {
+    value: number,
+    description: string
+}

+ 7 - 0
frontend_react/wbs-rechner-react/src/interfaces/wbs.ts

@@ -0,0 +1,7 @@
+export interface WBS {
+    wbsGranted: string,
+    yearlyAmount: number,
+    yearlyAmountMax: number,
+    difference: number,
+    percent: number;
+}

+ 42 - 0
frontend_react/wbs-rechner-react/src/service/wbsService.ts

@@ -0,0 +1,42 @@
+import { Frequency } from "../interfaces/frequency";
+import { Type } from "../interfaces/type";
+import { Person } from "../interfaces/persons";
+import { WBS } from "../interfaces/wbs";
+
+export class WbsService {
+  private baseUrl = "http://localhost:3100";
+
+  async getTypes(): Promise<Array<Type>> {
+    const response = await fetch(`${this.baseUrl}/types`);
+    const data = await response.json();
+
+    return data.map((item: Type) => ({
+      value: item.value,
+      description: item.description,
+    }));
+  }
+
+  async getFrequencies(): Promise<Array<Frequency>> {
+    const response = await fetch(`${this.baseUrl}/frequencies`);
+    const data = await response.json();
+
+    return data.map((item: Frequency) => ({
+      value: item.value,
+      description: item.description,
+    }));
+  }
+
+  calculateWbs(person: Array<Person>): Promise<WBS> {
+    console.log(person)
+
+    console.log(JSON.stringify(person))
+
+    return fetch(`${this.baseUrl}/calculate`, {
+      method: "POST",
+      headers: { "Content-Type": "application/json" },
+      body: JSON.stringify(person),
+    })
+      .then((response) => response.json())
+      .then((data) => data as WBS);
+  }
+}