Skip to content

Commit

Permalink
2020 update (#1)
Browse files Browse the repository at this point in the history
* Clean up components

* add gitignore

* More cleanup

* Update styles and add clear and clear all

* Add crapio logo

* Add big styles

* Display results when using a continued expression

* Remove DS_Store files

* Rename index
  • Loading branch information
kevingrammer authored Jan 6, 2021
1 parent d0f719a commit 25d2fa1
Show file tree
Hide file tree
Showing 12 changed files with 6,227 additions and 167 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.DS_Store
30 changes: 15 additions & 15 deletions app/components/Button.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
import React from 'react';

class Button extends React.Component {
import React, { Component } from 'react';

class Button extends Component {
constructor(props) {
super(props);
this.handleButtonClick = this.handleButtonClick.bind(this);
}

handleButtonClick(e, button) {
e.preventDefault();
this.props.buttonClick(this.props.button);
}

render() {
const { button } = this.props;
return (
<div className="buttonContainer">

<button className="button"
onClick={e => this.handleButtonClick(e, this.props.button)}>
{this.props.button}
<button
className="button"
onClick={this.handleButtonClick}
tabIndex={0}
>
{button}
</button>

</div>
);
}

handleButtonClick(e, button) {
e.preventDefault();
this.props.buttonClick(button);
}

}

export default Button;
export default Button;
42 changes: 13 additions & 29 deletions app/components/ButtonRow.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
import React from 'react';

import Button from './Button';

class ButtonRow extends React.Component {

constructor(props) {
super(props);
}

render() {

return (
<div className="buttonRow">

{ this.props.buttons.map(button => {
return (
<Button
key={'button' + button}
button={button}
buttonClick={(button) => this.props.buttonClick(button)}
/>
);
})}

</div>
);
}

}

export default ButtonRow;
const ButtonRow = ({ buttonClick, buttons }) => (
<div className="buttonRow">
{buttons.map(button => (
<Button
key={'button-' + button}
button={button}
buttonClick={buttonClick}
/>
))}
</div>
);

export default ButtonRow;
50 changes: 14 additions & 36 deletions app/components/ButtonsContainer.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,17 @@
import React from 'react';

import ButtonRow from './ButtonRow';
import * as constants from '../constants';

class ButtonsContainer extends React.Component {

constructor(props) {
super(props);
this.state = {
buttons: constants.BUTTON_MAP
};
}

render() {

return (
<div className="buttonContainer">

{ this.state.buttons.map((row, i) => {
return (
<div key={'row' + i}>

<ButtonRow
buttons={row}
buttonClick={(button) => this.props.buttonClick(button)}
/>

</div>
);
})}

import { BUTTON_MAP } from '../constants';

const ButtonsContainer = ({ buttonClick, buttons }) => (
<div className="buttonContainer" role="group" aria-label="calculator buttons">
{BUTTON_MAP.map((row, i) => (
<div key={'row' + i}>
<ButtonRow
buttons={row}
buttonClick={buttonClick}
/>
</div>
);
}

}

export default ButtonsContainer;
))}
</div>
);
export default ButtonsContainer;
130 changes: 81 additions & 49 deletions app/components/CalculatorContainer.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import { getButtonType } from '../helpers';
import _ from 'lodash';

import ButtonsContainer from './ButtonsContainer';
import Screen from './Screen';
import '../styles.scss';

const shouldClearAll = ({ calcs, num1, prevButton, screenText }) => {
return prevButton === 'clear' && !screenText && (calcs.length > 0 || num1 !== null);
};

class CalculatorContainer extends React.Component {

Expand All @@ -15,34 +17,29 @@ class CalculatorContainer extends React.Component {
num1: null,
operator: null,
prevButton: null,
calcs: []
calcs: [],
};
this.onButtonClick = this.onButtonClick.bind(this);
this.clear = this.clear.bind(this);
}

render() {

return (
<div className="outsideContainer">
<div className="calcContainer">

<Screen value={this.state.screenText} />

<ButtonsContainer
buttonClick={(button) => this.onButtonClick(button)}
/>

</div>

<hr />
clear() {
if (shouldClearAll(this.state)) {
this.setState({
screenText: '',
num1: null,
operator: null,
prevButton: null,
calcs: [],
});
} else {
this.setState({
screenText: '',
operator: null,
prevButton: 'clear',
});
}

<div className="calcsList">
{this.state.calcs.map((expression, i) => {
return <p key={i}>{expression}</p>
})}
</div>
</div>
);
}

// Helper method to get the current expression.
Expand Down Expand Up @@ -71,19 +68,27 @@ class CalculatorContainer extends React.Component {
break;
}

// @todo This needs to move, probably outside the calc container,
// definitely should not be setting state within this method.
this.setState({
calcs: [n1 + ' ' + operator + ' ' + n2 + ' = ' + result, ...this.state.calcs]
calcs: [
n1 + ' ' + operator + ' ' + n2 + ' = ' + result,
...this.state.calcs
]
});

return result;
}

onButtonClick (button) {

let buttonType = getButtonType(button);
let state = this.state;
const buttonType = getButtonType(button);
const {
num1,
num2,
operator,
prevButton,
screenText,
showingResult,
} = this.state;

// Regardless of the button clicked, let's keep track of the previous
// button click.
Expand All @@ -93,78 +98,105 @@ class CalculatorContainer extends React.Component {

switch(buttonType) {
case 'digit':
if(state.prevButton === '=') {
if(prevButton === '=') {
// If we just evaluated an expression, replace the screen text
// with the new digit, we are starting a new expression.
newState.screenText = button;
} else {
newState.screenText = state.screenText + button;
newState.screenText = showingResult ? button : screenText + button;
newState.showingResult = false;
}
this.setState(newState);
break;

case 'operator':
if (state.prevButton === '=') {
if (prevButton === '=') {
// If we just evaluated an expression, replace the operator
// and set num1 to the previous result.
newState.num1 = state.screenText;
newState.num1 = screenText;
newState.screenText = '';
newState.operator = button;
this.setState(newState);

} else if (!state.screenText.length) {
} else if (!screenText.length) {
// We can't handle negatives yet, need a separate button.

// if (button === '-') {
// newState.screenText = '-';
// this.setState(newState);
// }

} else if (!state.num1) {
newState.num1 = Number(state.screenText);
} else if (!num1) {
newState.num1 = Number(screenText);
newState.operator = button;
newState.screenText = '';
this.setState(newState);

} else if (!isNaN(Number(state.screenText))) {
} else if (!isNaN(Number(screenText))) {
// Handles the case where user inputs "3,+,5,-",
// should display result of "3+5" and setup "{result} - ".
let result = this.evaluateExpression(state.num1, state.screenText, state.operator);
let result = this.evaluateExpression(num1, screenText, operator);
// @todo Should display the result as screen text, but will need to
// implement a new way to know when previous action was evaluating
// an expression so that the next digit entered will replace the
// screen text.
newState.screenText = '';
newState.screenText = result;
newState.showingResult = true;
newState.num1 = result;
// newState.num2 = state.screenText;
newState.operator = button;
this.setState(newState);
}
break;

case 'evaluate':

if(state.prevButton === '=') {
if(prevButton === '=') {
// Repeat the previous calculation.
if(!isNaN(Number(state.screenText)) && state.num2 && state.operator) {
newState.screenText = this.evaluateExpression(state.screenText, state.num2, state.operator);
if(!isNaN(Number(screenText)) && num2 && operator) {
newState.screenText = this.evaluateExpression(screenText, num2, operator);
}

} else if (state.num1 && state.operator && state.screenText.length && !isNaN(Number(state.screenText))) {
} else if (num1 && operator && screenText.length && !isNaN(Number(screenText))) {
// If we have an complete expression, evaluate it.
newState.screenText = this.evaluateExpression(state.num1, state.screenText, state.operator);
newState.screenText = this.evaluateExpression(num1, screenText, operator);
newState.num1 = null;
newState.num2 = state.screenText;
newState.num2 = screenText;
}
this.setState(newState);
break;

default:
// This shouldn't happen!
console.log('unhandled button click', button);
console.error('Unhandled button click', { button });
break;
}
}

render() {
return (
<div className="outsideContainer">
<div className="calcContainer">
<div className="calcTitle">Crapio</div>
<Screen value={this.state.screenText} />
<ButtonsContainer buttonClick={this.onButtonClick} />
<button
className="clearButton"
onClick={this.clear}
>
{shouldClearAll(this.state) ? 'clear all' : 'clear'}
</button>
</div>

<hr />

<div className="calcsList">
{this.state.calcs.map((expression, i) => {
return <p key={i}>{expression}</p>
})}
</div>
</div>
);
}
}

export default CalculatorContainer;
export default CalculatorContainer;
Loading

0 comments on commit 25d2fa1

Please sign in to comment.