Skip to content

Commit

Permalink
Merge pull request #4 from Kakalanp/events
Browse files Browse the repository at this point in the history
Events
  • Loading branch information
Kakalanp committed Mar 17, 2022
2 parents 4d9afdb + 30db131 commit 9859885
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 72 deletions.
59 changes: 53 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
"big-js": "^3.1.3",
"big.js": "^6.1.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "5.0.0",
Expand Down
108 changes: 43 additions & 65 deletions src/components/Calculator.js
Original file line number Diff line number Diff line change
@@ -1,69 +1,47 @@
import React from 'react';
import styles from './Calculator.module.css';
import calculate from '../logic/calculate';

export default function Calculator() {
return (
<div className={styles.calculator}>
<div className={styles.calculator__input}>
<p>0</p>
</div>
<div className={styles.calculator__button__grey}>
<p>AC</p>
</div>
<div className={styles.calculator__button__grey}>
<p>+/-</p>
</div>
<div className={styles.calculator__button__grey}>
<p>%</p>
</div>
<div className={styles.calculator__button__orange}>
<p>÷</p>
</div>
<div className={styles.calculator__button__grey}>
<p>7</p>
</div>
<div className={styles.calculator__button__grey}>
<p>8</p>
</div>
<div className={styles.calculator__button__grey}>
<p>9</p>
</div>
<div className={styles.calculator__button__orange}>
<p>x</p>
</div>
<div className={styles.calculator__button__grey}>
<p>4</p>
</div>
<div className={styles.calculator__button__grey}>
<p>5</p>
</div>
<div className={styles.calculator__button__grey}>
<p>6</p>
</div>
<div className={styles.calculator__button__orange}>
<p>-</p>
</div>
<div className={styles.calculator__button__grey}>
<p>1</p>
</div>
<div className={styles.calculator__button__grey}>
<p>2</p>
</div>
<div className={styles.calculator__button__grey}>
<p>3</p>
</div>
<div className={styles.calculator__button__orange}>
<p>+</p>
</div>
<div className={`${styles.calculator__button__grey} ${styles.calculator__button__zero}`}>
<p>0</p>
</div>
<div className={styles.calculator__button__grey}>
<p>.</p>
</div>
<div className={styles.calculator__button__orange}>
<p>=</p>
</div>
</div>
);
export default class Calculator extends React.Component {
constructor(props) {
super(props);
this.state = {
total: 0,
next: null,
operation: null,
};
this.clickHandler = this.clickHandler.bind(this);
}

clickHandler(e) {
this.setState((state) => calculate(state, e.target.textContent));
}

render() {
const { total, operation, next } = this.state;
const buttonList = ['AC', '+/-', '%', '÷', '7', '8', '9', 'x', '4', '5', '6', '-', '1', '2', '3', '+', '0', '.', '='];
return (
<div className={styles.calculator}>
<div className={styles.calculator__result}>
<p>
{total}
{' '}
{operation}
{' '}
{next}
</p>
</div>
{buttonList.map((item, index) => {
let name = styles.calculator__button__grey;
if ((index + 1) % 4 === 0 || index === 18) { name = styles.calculator__button__orange; }
if (index === 16) { name = `${styles.calculator__button__grey} ${styles.calculator__button__zero}`; }
return (
<div key={item.id} className={name} onClick={this.clickHandler} onKeyPress={(e) => { if (e.key === 'Enter') this.clickHandler(); }} role="button" tabIndex={0}>
<p style={{ userSelect: 'none' }}>{item}</p>
</div>
);
})}
</div>
);
}
}
2 changes: 1 addition & 1 deletion src/components/Calculator.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ div p {
font-size: 1.5rem;
}

.calculator__input {
.calculator__result {
grid-column: 1 / 5;
background-color: #858693;
text-align: right;
Expand Down
129 changes: 129 additions & 0 deletions src/logic/calculate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import operate from './operate';

function isNumber(item) {
return !!item.match(/[0-9]+/);
}

/**
* Given a button name and a calculator data object, return an updated
* calculator data object.
*
* Calculator data object contains:
* total:s the running total
* next:String the next number to be operated on with the total
* operation:String +, -, etc.
*/
export default function calculate(obj, buttonName) {
if (buttonName === 'AC') {
return {
total: null,
next: null,
operation: null,
};
}

if (isNumber(buttonName)) {
if (buttonName === '0' && obj.next === '0') {
return {};
}
// If there is an operation, update next
if (obj.operation) {
if (obj.next) {
return { ...obj, next: obj.next + buttonName };
}
return { ...obj, next: buttonName };
}
// If there is no operation, update next and clear the value
if (obj.next) {
return {
next: obj.next + buttonName,
total: null,
};
}
return {
next: buttonName,
total: null,
};
}

if (buttonName === '.') {
if (obj.next) {
if (obj.next.includes('.')) {
return { ...obj };
}
return { ...obj, next: `${obj.next}.` };
}
if (obj.operation) {
return { next: '0.' };
}
if (obj.total) {
if (obj.total.includes('.')) {
return {};
}
return { total: `${obj.total}.` };
}
return { total: '0.' };
}

if (buttonName === '=') {
if (obj.next && obj.operation) {
return {
total: operate(obj.total, obj.next, obj.operation),
next: null,
operation: null,
};
}
// '=' with no operation, nothing to do
return {};
}

if (buttonName === '+/-') {
if (obj.next) {
return { ...obj, next: (-1 * parseFloat(obj.next)).toString() };
}
if (obj.total) {
return { ...obj, total: (-1 * parseFloat(obj.total)).toString() };
}
return {};
}

// Button must be an operation

// When the user presses an operation button without having entered
// a number first, do nothing.
// if (!obj.next && !obj.total) {
// return {};
// }

// User pressed an operation after pressing '='
if (!obj.next && obj.total && !obj.operation) {
return { ...obj, operation: buttonName };
}

// User pressed an operation button and there is an existing operation
if (obj.operation) {
if (obj.total && !obj.next) {
return { ...obj, operation: buttonName };
}

return {
total: operate(obj.total, obj.next, obj.operation),
next: null,
operation: buttonName,
};
}

// no operation yet, but the user typed one

// The user hasn't typed a number yet, just save the operation
if (!obj.next) {
return { operation: buttonName };
}

// save the operation and shift 'next' into 'total'
return {
total: obj.next,
next: null,
operation: buttonName,
};
}

0 comments on commit 9859885

Please sign in to comment.