Addition.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. import React, { useState, useEffect, useRef } from "react";
  2. import Button from '@material-ui/core/Button';
  3. import Dialog from '@material-ui/core/Dialog';
  4. import DialogActions from '@material-ui/core/DialogActions';
  5. import DialogContent from '@material-ui/core/DialogContent';
  6. import DialogContentText from '@material-ui/core/DialogContentText';
  7. import DialogTitle from '@material-ui/core/DialogTitle';
  8. import "./App.css";
  9. let imdtRes;
  10. let imdtResIdx;
  11. let resArr = [];
  12. function Addition() {
  13. const [input, setInput] = useState(""); // initial user input like 34+56.7
  14. const [result, setResult] = useState(0); // real result of calculation
  15. const [carryArr, setCarryArr] = useState([]); // array of carries [1","0"]
  16. const [commaIdx, setCommaIdx] = useState(0); // int: comma position
  17. const [numbers, setNumbers] = useState(0); // array of arrays with input numbers
  18. const [showAlert, setShowAlert] = useState(false);
  19. const handleInput = (e) => {
  20. setInput(e.target.value);
  21. // TODO: reset results, etc.
  22. }
  23. const handleResChange = (e, nosLeft) => {
  24. if(typeof e === "string"){
  25. imdtRes = e;
  26. let carryArrCopy = [...carryArr]
  27. carryArrCopy[nosLeft] = carryArrCopy[nosLeft+1]
  28. setCarryArr(carryArrCopy)
  29. }else{
  30. imdtRes = e.target.value;
  31. }
  32. if(imdtRes === ""){
  33. console.log(resArr, resArr.length)
  34. let no = resArr.shift();
  35. console.log(resArr, "n", no);
  36. }else{
  37. resArr.unshift(imdtRes);
  38. if(nosLeft === 0){
  39. console.log("set true")
  40. setShowAlert(true);
  41. // addResultToDiv(resArr);
  42. let resCalc = resArr.join("");
  43. resCalc = parseFloat(resCalc);
  44. // if(resCalc === result){
  45. // alert("success")
  46. // resCalc = 0;
  47. // }else{
  48. // alert("error")
  49. // resCalc = 0;
  50. // }
  51. }
  52. }
  53. }
  54. const handleCarryChange = (e, noOfDigits, idx) => {
  55. if(typeof carryArr === "undefined"){
  56. setCarryArr(Array(noOfDigits).fill("-"));
  57. }
  58. let carryArrCopy = [...carryArr]
  59. carryArrCopy[idx] = e.target.value
  60. setCarryArr(carryArrCopy);
  61. }
  62. const handleSubmit = (e) => {
  63. // setInput("1,3+22,450");
  64. startCalculation();
  65. e.preventDefault(); // avoid page reload
  66. }
  67. const afterCommaLen = (number) => {
  68. let noStrList = number.toString().split(".");
  69. if (noStrList.length > 1){
  70. return noStrList[1].length
  71. }
  72. return 0
  73. }
  74. const addNumbersToDiv = (numbers, noOfDigits) => {
  75. for (let idx in numbers){
  76. let no = numbers[idx].join("")
  77. if(idx===numbers.length-1){
  78. no = "+ " + no
  79. }
  80. let pNo = "<p>" + no + "</p>"
  81. document.getElementById("overview").innerHTML += pNo;
  82. }
  83. document.getElementById("overview").innerHTML += carryArr.join("");
  84. document.getElementById("overview").innerHTML += "<hr>";
  85. }
  86. const addResultToDiv = () => {
  87. let res = "<p>" + resArr.join("") + "</p>"
  88. document.getElementById("overview").innerHTML += res;
  89. }
  90. function numbersToArrOfArr(numbers) {
  91. let befComma = Math.max(...numbers).toString().split(".")[0].length;
  92. let afterComma = Math.max(...numbers.map(x => afterCommaLen(x)));
  93. let withComma = Math.max(...numbers.map(x => x.toString().indexOf(".")));
  94. let arrLength;
  95. if(withComma < 0){ // no comma found
  96. arrLength = befComma;
  97. }else{
  98. arrLength = befComma + afterComma + 1; // add comma and after comma len
  99. }
  100. let numbersArr = numbers.map(x => x.toString().split(""));
  101. for (let numArr of numbersArr){
  102. let commaIdx = numArr.indexOf(".");
  103. // without comma, add before
  104. while(commaIdx===-1 && numArr.length < befComma){
  105. numArr.unshift("&nbsp;"); // add " " before comma
  106. }
  107. // without comma, add after
  108. while(commaIdx===-1 && numArr.length < arrLength){
  109. numArr.push("&nbsp;"); // add " " after comma
  110. }
  111. // with comma, add before
  112. while(commaIdx>-1 && commaIdx!==befComma){
  113. numArr.unshift("&nbsp;"); // add " " before comma
  114. commaIdx = numArr.indexOf(".");
  115. }
  116. // with comma, add after
  117. while(numArr.length < arrLength){
  118. numArr.push("&nbsp;"); // add " " after comma
  119. }
  120. numArr.unshift("&nbsp;"); // for carry
  121. }
  122. document.getElementById("overview").innerHTML = "";
  123. setNumbers(numbersArr);
  124. setCommaIdx(befComma+1);
  125. addNumbersToDiv(numbersArr, arrLength);
  126. // TODO: assert all have same length and comma at same index?
  127. return [numbersArr, befComma]
  128. }
  129. const startCalculation = () => {
  130. if (input.includes("+")){
  131. let numbers = input.split("+").map(x => parseFloat(x.replace(",",".")));
  132. let commaIdx = -1;
  133. setResult(numbers.reduce((x,y) => x+y, 0));
  134. [numbers, commaIdx] = numbersToArrOfArr(numbers);
  135. }
  136. }
  137. const ResultCarryForm = ({handleResChange, handleCarryChange}) => {
  138. let resInputField = useRef(null);
  139. let carryInputField = useRef(null);
  140. // focus the input field
  141. useEffect(()=>{
  142. if(resInputField.current && resInputField.current.value === ""){
  143. resInputField.current.focus();
  144. }
  145. },[])
  146. let labelText = "";
  147. let nosLeft = imdtResIdx;
  148. let noOfDigits = 0;
  149. let carryText = "Übertrag = ";
  150. if(typeof numbers === "object" && imdtResIdx !== -1){
  151. if(typeof imdtResIdx === "undefined"){
  152. noOfDigits = Math.min(...numbers.map(n => n.length));
  153. imdtResIdx = noOfDigits-1;
  154. }
  155. if(imdtResIdx === commaIdx){
  156. handleResChange(".", nosLeft)
  157. imdtResIdx = imdtResIdx - 1;
  158. }
  159. for (let n in numbers){ // iterate numbers
  160. if(nosLeft === 1 && carryArr[1] === "0"){
  161. nosLeft = 0;
  162. imdtResIdx = -1;
  163. handleResChange("&nbsp;", 0)
  164. return <></>
  165. }
  166. let no = numbers[parseInt(n)][imdtResIdx];
  167. if(no === "" || no === "&nbsp;"){
  168. no = 0;
  169. }
  170. labelText += no;
  171. if (parseInt(n) === numbers.length - 1){
  172. if(carryArr[imdtResIdx+1]!=="undefind" && carryArr[imdtResIdx+1] > 0){
  173. labelText += " + " + carryArr[imdtResIdx+1].toString();
  174. }
  175. labelText += " = ";
  176. }else{
  177. labelText += " + "; // TODO: replace with -/* etc.
  178. }
  179. }
  180. if(carryArr[imdtResIdx] > -1){
  181. imdtRes = -1;
  182. imdtResIdx = imdtResIdx - 1;
  183. nosLeft = nosLeft - 1;
  184. }
  185. return (
  186. <form>
  187. <label htmlFor="input_result" id="input_result_label">
  188. {labelText}
  189. </label>
  190. <input
  191. onChange={(e) => handleResChange(e, nosLeft)}
  192. type="text" id="input_result" size="2" tabIndex={1}
  193. aria-labelledby="input_result_label" aria-required="true"
  194. ref={resInputField}/>
  195. <br/>
  196. <label htmlFor="input_carry" id="input_carry_label">
  197. {carryText}
  198. </label>
  199. <input
  200. onChange={(e) => handleCarryChange(e, noOfDigits, imdtResIdx)}
  201. type="text" id="input_carry" size="2" tabIndex={2}
  202. aria-labelledby="input_carry_label" aria-required="true"
  203. ref={carryInputField}/>
  204. </form>
  205. );
  206. }else{
  207. return (
  208. <>
  209. </>
  210. );
  211. }
  212. }
  213. const showIdmtResults = () => {
  214. setShowAlert(false);
  215. let realResArr = result.toString().split("");
  216. while(realResArr.length < resArr.length){
  217. realResArr.unshift("&nbsp;"); // add " " before
  218. }
  219. let carries = carryArr.map(x => x || "0")
  220. carries.push("0");
  221. while(carries.length < resArr.length){
  222. carries.unshift("0"); // add "0" before
  223. }
  224. let foundComma = false;
  225. for (let i=0; i<resArr.length-1; i++) {
  226. let text = "";
  227. let trueNumbers = false;
  228. let idxNumbers = resArr.length - i - 1;
  229. let idxCarry = carries.length - i - 1;
  230. let realSum = 0;
  231. for (let j=0; j<numbers.length; j++) {
  232. let no = numbers[j][idxNumbers];
  233. if (no!=="." && no!=="&nbsp;"){
  234. trueNumbers = true;
  235. realSum += parseInt(no);
  236. }
  237. text += no
  238. if (j<numbers.length-1){
  239. text += " + "
  240. }
  241. }
  242. // ignore indexes without real digits
  243. if (resArr[idxNumbers]!=="&nbsp;" || carries[idxCarry]!=="&nbsp;"){
  244. trueNumbers = true;
  245. }
  246. // carry array has no "."
  247. if (resArr[idxNumbers] === "."){
  248. foundComma = true;
  249. trueNumbers = false;
  250. }
  251. if (foundComma){
  252. idxCarry += 1;
  253. }
  254. // add carry only if > 0
  255. if (carries[idxCarry]!=="0"){
  256. realSum += parseInt(carries[idxCarry]);
  257. text += " + " + carries[idxCarry] + " Übertrag"
  258. }
  259. let realCarry = parseInt(realSum/10).toString()
  260. realSum = (realSum % 10).toString()
  261. text += " = "
  262. if (trueNumbers){
  263. text += resArr[idxNumbers]
  264. text = text.replace("&nbsp;", "0")
  265. text += resArr[idxNumbers]===realSum && carries[idxCarry-1]===realCarry ? "\t\tRichtig" : "\t\tFalsch";
  266. let paragraph = document.createElement("p");
  267. paragraph.innerHTML = text
  268. document.getElementById("idmtResultSteps").appendChild(paragraph);
  269. let btn = document.createElement("button");
  270. btn.innerHTML = "bearbeiten: " + text;
  271. btn.addEventListener("click", () => startOver(i));
  272. document.getElementById("idmtResultSteps").appendChild(btn);
  273. }
  274. }
  275. let btnSubmit = document.createElement("button");
  276. btnSubmit.innerHTML = "submit result";
  277. btnSubmit.addEventListener("click", () => console.log("end"));
  278. document.getElementById("idmtResultSteps").appendChild(btnSubmit);
  279. }
  280. const startOver = (idx) => {
  281. console.log("clicked at " + idx)
  282. }
  283. const handleClose = () => {
  284. setShowAlert(false);
  285. };
  286. const Alert = () => {
  287. return(
  288. <div>
  289. <Dialog
  290. open={showAlert}
  291. onClose={handleClose}
  292. aria-labelledby="alert-dialog-title"
  293. aria-describedby="alert-dialog-description"
  294. >
  295. <DialogTitle id="alert-dialog-title">{"Ergebnis überprüfen oder abgeben?"}</DialogTitle>
  296. <DialogContent>
  297. <DialogContentText id="alert-dialog-description">
  298. Willst du dein Ergebnis nochmal überprüfen oder gleich abgeben?
  299. </DialogContentText>
  300. </DialogContent>
  301. <DialogActions>
  302. <Button onClick={showIdmtResults} color="primary" autoFocus>
  303. Prüfen
  304. </Button>
  305. <Button onClick={handleClose} color="primary">
  306. Abgeben
  307. </Button>
  308. </DialogActions>
  309. </Dialog>
  310. </div>
  311. )};
  312. return (
  313. <div id="content">
  314. <h1>Addition</h1>
  315. <form onSubmit={(e) => handleSubmit(e)}>
  316. <label for="calculationInput">
  317. Rechnung:
  318. </label>
  319. <input
  320. type="text"
  321. id="calculationInput"
  322. onChange={(e) => handleInput(e)}
  323. aria-label="Rechnung"
  324. aria-required="true"/>
  325. <input type="submit" value="berechnen"/>
  326. </form>
  327. <div id="overview"></div>
  328. <div id="calculation">
  329. <ResultCarryForm
  330. handleResChange={handleResChange}
  331. handleCarryChange={handleCarryChange}/>
  332. </div>
  333. <div id="idmtResultSteps"></div>
  334. <Alert/>
  335. </div>
  336. );
  337. }
  338. export default Addition;