123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- import React, { useState, useEffect, useRef } from "react";
- import Button from '@material-ui/core/Button';
- import Dialog from '@material-ui/core/Dialog';
- import DialogActions from '@material-ui/core/DialogActions';
- import DialogContent from '@material-ui/core/DialogContent';
- import DialogContentText from '@material-ui/core/DialogContentText';
- import DialogTitle from '@material-ui/core/DialogTitle';
- import DataGrid, {Column} from 'devextreme-react/data-grid';
- import "./App.css";
- let imdtRes;
- let imdtResIdx;
- let resArr = [];
- function Addition() {
- const [input, setInput] = useState(""); // initial user input like 34+56.7
- const [realResult, setRealResult] = useState(0); // real result of calculation
- const [carryArr, setCarryArr] = useState([]); // array of carries [1","0"]
- const [commaIdx, setCommaIdx] = useState(0); // int: comma position
- const [numbers, setNumbers] = useState(0); // array of arrays with input numbers
- const [showAlert, setShowAlert] = useState(false);
- const [numbersGrid, setNumbersGrid] = useState([{id: 1, number: ""}]);
- const [resultsGrid, setResultsGrid] = useState([{id: 1, number: ""}]);
- // focus the input field
- let calculationInput = useRef(null);
- useEffect(()=>{
- if(calculationInput.current && calculationInput.current.value === ""){
- calculationInput.current.focus();
- }
- },[])
- const handleInput = (e) => {
- setInput(e.target.value);
- }
- const handleResChange = (e, nosLeft) => {
- if(typeof e === "string"){
- imdtRes = e;
- let carryArrCopy = [...carryArr]
- carryArrCopy[nosLeft] = carryArrCopy[nosLeft+1]
- setCarryArr(carryArrCopy)
- }else{
- imdtRes = e.target.value;
- }
- if(imdtRes === ""){
- resArr.shift();
- }else{
- resArr.unshift(imdtRes);
- if(nosLeft === 0){
- setShowAlert(true);
- }
- }
- }
- const handleCarryChange = (e, noOfDigits, idx) => {
- if(typeof carryArr === "undefined"){
- setCarryArr(Array(noOfDigits).fill("-"));
- }
- let carryArrCopy = [...carryArr]
- carryArrCopy[idx] = e.target.value
- setCarryArr(carryArrCopy);
- }
- const handleSubmit = (e) => {
- startCalculation();
- e.preventDefault(); // avoid page reload
- }
- const afterCommaLen = (number) => {
- let noStrList = number.toString().split(".");
- if (noStrList.length > 1){
- return noStrList[1].length
- }
- return 0
- }
- const addNumbersToDiv = (numbers, noOfDigits) => {
- console.log("---", carryArr.join(""))
- // document.getElementById("overview").innerHTML += carryArr.join("");
- }
- function numbersToArrOfArr(numbers) {
- let befComma = Math.max(...numbers).toString().split(".")[0].length;
- let afterComma = Math.max(...numbers.map(x => afterCommaLen(x)));
- let withComma = Math.max(...numbers.map(x => x.toString().indexOf(".")));
- let arrLength;
- if(withComma < 0){ // no comma found
- arrLength = befComma;
- }else{
- arrLength = befComma + afterComma + 1; // add comma and after comma len
- }
- let numbersArr = numbers.map(x => x.toString().split(""));
- for (let numArr of numbersArr){
- let commaIdx = numArr.indexOf(".");
- // without comma, add before
- while(commaIdx===-1 && numArr.length < befComma){
- numArr.unshift(" "); // add " " before comma
- }
- // without comma, add after
- while(commaIdx===-1 && numArr.length < arrLength){
- numArr.push(" "); // add " " after comma
- }
- // with comma, add before
- while(commaIdx>-1 && commaIdx!==befComma){
- numArr.unshift(" "); // add " " before comma
- commaIdx = numArr.indexOf(".");
- }
- // with comma, add after
- while(numArr.length < arrLength){
- numArr.push(" "); // add " " after comma
- }
- numArr.unshift(" "); // for carry
- }
- setNumbers(numbersArr);
- const nrGrid = []
- for (let noIdx in numbersArr){
- let nr = numbersArr[noIdx].join("").replace(/ /g, " ");
- if (noIdx == numbersArr.length-1){
- nr = "+ " + nr;
- }
- nrGrid.push({id: parseInt(noIdx)+3, number: nr});
- }
- setNumbersGrid(nrGrid);
- setCommaIdx(befComma+1);
- return [numbersArr, arrLength]
- }
- const startCalculation = () => {
- if (input.includes("+")){
- let numbers = input.split("+").map(x => parseFloat(x.replace(",",".")));
- setRealResult(numbers.reduce((x,y) => x+y, 0));
- let [numbersArr, arrLength] = numbersToArrOfArr(numbers);
- addNumbersToDiv(numbersArr, arrLength);
- }
- }
- const ResultCarryForm = ({handleResChange, handleCarryChange}) => {
- let resInputField = useRef(null);
- let carryInputField = useRef(null);
- // focus the input field
- useEffect(()=>{
- if(resInputField.current && resInputField.current.value === ""){
- resInputField.current.focus();
- }
- },[])
- let labelText = "";
- let nosLeft = imdtResIdx + 1;
- let noOfDigits = 0;
- let carryText = "Übertrag = ";
- if(typeof numbers === "object" && imdtResIdx !== -1){
- if(typeof imdtResIdx === "undefined"){
- noOfDigits = Math.min(...numbers.map(n => n.length));
- imdtResIdx = noOfDigits-1;
- }
- if(imdtResIdx === commaIdx){
- handleResChange(".", nosLeft)
- imdtResIdx = imdtResIdx - 1;
- }
- for (let n in numbers){ // iterate numbers
- if(nosLeft === 1 && carryArr[0] === "0"){
- nosLeft = 0;
- imdtResIdx = -1;
- handleResChange(" ", 0)
- return <></>
- }
- let digit = numbers[parseInt(n)][imdtResIdx];
- if(digit === "" || digit === " "){
- digit = 0;
- }
- labelText += digit;
- if (parseInt(n) === numbers.length - 1){
- if(carryArr[imdtResIdx+1]!=="undefind" && carryArr[imdtResIdx+1] > 0){
- labelText += " + " + carryArr[imdtResIdx+1].toString();
- }
- labelText += " = ";
- }else{
- labelText += " + "; // TODO: replace with -/* etc.
- }
- }
- if(carryArr[imdtResIdx] > -1 || imdtResIdx === noOfDigits-1){
- imdtRes = -1;
- imdtResIdx = imdtResIdx - 1;
- nosLeft = nosLeft - 1;
- }
- return (
- <form>
- <label htmlFor="input_result" id="input_result_label">
- {labelText}
- </label>
- <input
- onChange={(e) => handleResChange(e, nosLeft)}
- type="text" id="input_result" size="2" tabIndex={1}
- aria-labelledby="input_result_label" aria-required="true"
- ref={resInputField}/>
- <br/>
- <label htmlFor="input_carry" id="input_carry_label">
- {carryText}
- </label>
- <input
- onChange={(e) => handleCarryChange(e, noOfDigits, imdtResIdx)}
- type="text" id="input_carry" size="2" tabIndex={2}
- aria-labelledby="input_carry_label" aria-required="true"
- ref={carryInputField}/>
- </form>
- );
- }else{
- return (
- <>
- </>
- );
- }
- }
- const showIdmtResults = () => {
- setShowAlert(false);
- let realResArr = realResult.toString().split("");
- while(realResArr.length < resArr.length){
- realResArr.unshift(" "); // add " " before
- }
- let carries = carryArr.map(x => x || "0")
- carries.push("0");
- while(carries.length < resArr.length){
- carries.unshift("0"); // add "0" before
- }
- let foundComma = false;
- for (let i=0; i<resArr.length-1; i++) {
- let text = "";
- let trueNumbers = false;
- let idxNumbers = resArr.length - i - 1;
- let idxCarry = carries.length - i - 1;
- let realSum = 0;
- for (let j=0; j<numbers.length; j++) {
- let no = numbers[j][idxNumbers];
- if (no!=="." && no!==" "){
- trueNumbers = true;
- realSum += parseInt(no);
- }
- text += no
- if (j<numbers.length-1){
- text += " + "
- }
- }
- // ignore indexes without real digits
- if (resArr[idxNumbers]!==" " || carries[idxCarry]!==" "){
- trueNumbers = true;
- }
- // carry array has no "."
- if (resArr[idxNumbers] === "."){
- foundComma = true;
- trueNumbers = false;
- }
- if (foundComma){
- idxCarry += 1;
- }
- // add carry only if > 0
- if (carries[idxCarry]!=="0"){
- realSum += parseInt(carries[idxCarry]);
- text += " + " + carries[idxCarry] + " Übertrag"
- }
- let realCarry = parseInt(realSum/10).toString()
- realSum = (realSum % 10).toString()
- text += " = "
- if (trueNumbers){
- text += resArr[idxNumbers]
- text = text.replace(" ", "0")
- text += resArr[idxNumbers]===realSum && carries[idxCarry-1]===realCarry ? "\t\tRichtig" : "\t\tFalsch";
- let paragraph = document.createElement("p");
- paragraph.innerHTML = text
- document.getElementById("idmtResultSteps").appendChild(paragraph);
- let btn = document.createElement("button");
- btn.innerHTML = "bearbeiten: " + text;
- btn.addEventListener("click", () => startOver(i));
- document.getElementById("idmtResultSteps").appendChild(btn);
- }
- }
- let btnSubmit = document.createElement("button");
- btnSubmit.innerHTML = "submit result";
- btnSubmit.addEventListener("click", () => console.log("end"));
- document.getElementById("idmtResultSteps").appendChild(btnSubmit);
- }
- const startOver = (idx) => {
- console.log("clicked at " + idx)
- }
- const finishCalculation = () => {
- setShowAlert(false);
- let resCalc = resArr.filter(n => n !== " ").join("")
- setResultsGrid([{number: resCalc}]);
- resCalc = parseFloat(resCalc);
- let message = ""
- if(resCalc === realResult){
- message = "Richtig!"
- }else{
- message = "Das ist leider falsch."
- }
- message = "<p>" + message + "</p>"
- document.getElementById("finishCalculation").innerHTML = message
- }
- const Alert = () => {
- return(
- <div>
- <Dialog
- open={showAlert}
- onClose={finishCalculation}
- aria-labelledby="alert-dialog-title"
- aria-describedby="alert-dialog-description"
- >
- <DialogTitle id="alert-dialog-title">{"Ergebnis überprüfen oder abgeben?"}</DialogTitle>
- <DialogContent>
- <DialogContentText id="alert-dialog-description">
- Willst du dein Ergebnis nochmal überprüfen oder gleich abgeben?
- </DialogContentText>
- </DialogContent>
- <DialogActions>
- <Button onClick={showIdmtResults} color="primary" autoFocus>
- Prüfen
- </Button>
- <Button onClick={finishCalculation} color="primary">
- Abgeben
- </Button>
- </DialogActions>
- </Dialog>
- </div>
- )};
- return (
- <div id="content">
- <h1>Addition</h1>
- <form onSubmit={(e) => handleSubmit(e)}>
- <label htmlFor="calculationInput">
- Rechnung:
- </label>
- <input
- type="text"
- id="calculationInput"
- onChange={(e) => handleInput(e)}
- aria-label="Rechnung"
- aria-required="true"
- ref={calculationInput}/>
- <input type="submit" value="berechnen"/>
- </form>
- <div id="overview">
- <DataGrid
- dataSource={numbersGrid}
- keyExpr="id"
- focusedRowEnabled={true}
- showBorders={true}
- showColumnHeaders={false}
- >
- <Column dataField="number" />
- </DataGrid>
- <hr></hr>
- <DataGrid
- dataSource={resultsGrid}
- focusedRowEnabled={true}
- showBorders={true}
- showColumnHeaders={false}
- >
- <Column dataField="number" />
- </DataGrid>
- </div>
- <div id="calculation">
- <ResultCarryForm
- handleResChange={handleResChange}
- handleCarryChange={handleCarryChange}/>
- </div>
- <div id="idmtResultSteps"></div>
- <div id="finishCalculation"></div>
- <Alert/>
- </div>
- );
- }
- export default Addition;
|