harunpehlivan
3/6/2018 - 3:19 PM

React Calculator

React Calculator

@import 'https://fonts.googleapis.com/css?family=Roboto+Mono';

:root {
	font-size: 18px;
}

@media only screen and (min-width: 768px) {
	:root { font-size: 24px }
}

$buttonSize: 4rem;
$black: #343838;
$transBlack: rgba(0, 0, 0, 0.3);
$gold: #CDB380;
$cloud: #5E6F8C;
$purp: #542437;


body{
	margin: 0;
	padding: 0;
	height: 100vh;
	display: flex;
	justify-content: center;
	align-items: center;
	font:{
		family: 'Roboto Mono';
		size: $buttonSize / 4;
	}
	background: linear-gradient(to bottom right, $purp 0%, $gold 100%) 100% no-repeat;
}
button{
	width: $buttonSize;
	height: $buttonSize;
	font:{
		family: 'Roboto Mono';
		size: 16px;
	}
	background: none;
	color: $gold;
	border: none;
	cursor: pointer;
	transition: color 300ms ease-in-out;
	&:hover{
		color: $cloud;
	}
	&:focus{
		outline: none;
	}
}
.calculator {
	width: 4 * $buttonSize;
	background: $black;
	box-shadow: 0 0 $buttonSize 0 $transBlack;
}
.calc-display{
	font-size: 18px;
	padding: $buttonSize / 2.5 $buttonSize / 3;
	text-align: right;
	color: $gold;
	border-bottom: 3px solid $cloud;
	box-shadow: 0 5px 21px -5px $transBlack;
}
.calc-numbers{
	width: 3 * $buttonSize;
	display: flex;
	justify-content: center;
	flex-wrap: wrap;
	float: left;
}
.calc-functions{
	float: left;
}
<script src="https://npmcdn.com/react@15.3.0/dist/react.min.js"></script>
<script src="https://npmcdn.com/react-dom@15.3.0/dist/react-dom.min.js"></script>
class Calculator extends React.Component{
	constructor(){
		super();
		this.state={
			displayVal: "0",
			calcVals: []
		};
	}
	_displayNum(num){
		if(this.state.displayVal.length > 19) { // Where var too long for display
			return;
		} else if(this.state.displayVal === "0" || this.state.displayVal === "Undefined! 😫") { // Where var is 0, or where result is undefined
 			this.setState({
				displayVal: num
			});
		} else if(this.state.displayVal.charAt(0) === "-" && this.state.displayVal.charAt(1) === "0") { // Fix to allow user to add - sign while displayed value is still 0
			this.setState({
				displayVal: `-${num}`
			});
		} 
		else {
			this.setState({
				displayVal: this.state.displayVal + num
			});
		}
	}
	_clearVals(){
		this.setState({
			displayVal: "0",
			calcVals: []
		});
	}
	_insDecimal(){
		if (this.state.displayVal.length > 19) {
			return;
		} else if (this.state.displayVal.indexOf(".") === -1) {
			this.setState({
				displayVal: this.state.displayVal + "."
			})
		} else {
			return;
		}
	}
	_swapSign(){
		const char = this.state.displayVal.charAt(0);
		if(char === "-") {
			this.setState({
				displayVal: this.state.displayVal.slice(1)
			});
		} else {
			this.setState({
				displayVal: "-" + this.state.displayVal
			});
		}
	}
	_addToCalc(oper){
		const currentVal = parseFloat(this.state.displayVal),
				calc = {
					val: currentVal,
					sign: oper
				},
				vals = [...this.state.calcVals];
		vals.push(calc);
		this.setState({
			displayVal: "0",
			calcVals: vals
		});
	}
	_calcResult(oper){
		const valsToCalc = [...this.state.calcVals],
				currentVal = parseFloat(this.state.displayVal);
		let result = 0;
		// Add current value to array
		valsToCalc.push({val: currentVal, sign: oper});
		for(let i = 0, x = valsToCalc.length; i < x; i++){
			// For first iteration, set result = to first value
			// This is so we can do sums between current and previous loop iteration
			if(i === 0) {
				result = valsToCalc[i].val;
			} else {
				// Referencing the previous iteration's sign
				switch(valsToCalc[i - 1].sign){
					case "+":
						result += valsToCalc[i].val;
						break;
					case "-":
						result -= valsToCalc[i].val;
						break;
					case "*":
						result *= valsToCalc[i].val;
						break;
					case "/":
						result /= valsToCalc[i].val;
						break;
					default:
						console.log("Something went wrong...");
				}
			}
		}
		// Catch if user divides by 0
		if(isNaN(result) || result === Infinity) {
			result = "Undefined! 😫";
		} else {
			result = result.toString();
		}
		// Set result on state
		this.setState({
			displayVal: result,
			calcVals: []
		});
	}
	render(){
		const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
					operations = ['+', '-', '*', '/', '='],
					functions = ['c', '±', '.'];
		return(
			<div className="calculator">
				<Display
					displayVal={this.state.displayVal}
				/>
				<Functions 
					functions={functions}
					_clearVals={this._clearVals.bind(this)}
					_insDecimal={this._insDecimal.bind(this)}
					_swapSign={this._swapSign.bind(this)}
				/>
				<Numbers 
					numbers={numbers}
					_displayNum={this._displayNum.bind(this)}
				/>
				<Operations
					operations={operations}
					_addToCalc={this._addToCalc.bind(this)}
					_calcResult={this._calcResult.bind(this)}
				/>
			</div>
		);
	}
};

class Operations extends React.Component{
	_handleOper(oper){
		switch (oper){
			case "+":
			case "-":
			case "*":
			case "/":
				this.props._addToCalc(oper);
				break;
			case "=":
				this.props._calcResult(oper);
				break;
			default:
				console.log("Something went wrong...");
		}
	}
	render(){
		return(
			<div className="calc-operations">
				{this.props.operations.map((operation) => {
					return <Button 
									 button={operation}
									 _handleOper={this._handleOper.bind(this)}
									/>;
				})}
			</div>
		);
	}
};

class Functions extends React.Component{
	_handleFunct(funct){
		// Conditional to call appropriate function
		switch (funct){
			case "c":
				this.props._clearVals();
				break;
			case "±":
				this.props._swapSign();
				break;
			case ".":
				this.props._insDecimal();
				break;
			default:
				console.log("Something went wrong...");
		}
	}
	render(){
		return(
			<div className="calc-functions">
				{this.props.functions.map((funct) => {
			 		return <Button
									 button={funct}
									 _handleFunct={this._handleFunct.bind(this)}
									/>;
				})}
			</div>
		);
	}
};

class Numbers extends React.Component{
	_handleNum(num){
		const parsedNum = num.toString();
		this.props._displayNum(parsedNum);
	}
	render(){
		return(
			<div className="calc-numbers">
				{this.props.numbers.map((number) => {
					return <Button 
									 button={number}
									 _handleNum={this._handleNum.bind(this)}
									/>;
				})}
			</div>
		);
	}
};

class Display extends React.Component{
	render(){
		return(
			<div className="calc-display">
				{this.props.displayVal}
			</div>
		);
	}
};

class Button extends React.Component{
	_handleClick(e){
		// Conditional to handle different types of buttons
		switch (this.props.button){
			case 0:
			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			case 7:
			case 8:
			case 9:
				this.props._handleNum(this.props.button);
				break;
			case "c":
			case "±":
			case ".":
				this.props._handleFunct(this.props.button);
				break;
			case "+":
			case "-":
			case "*":
			case "/":
			case "=":
				this.props._handleOper(this.props.button);
				break;
		}
	}
	render(){
		return(
			<button name={this.props.button} onClick={this._handleClick.bind(this)}>
				{this.props.button}
			</button>
		);
	}
};

// Render app
ReactDOM.render(
	<Calculator />,
	document.querySelector('#app')
);

React Calculator

Calculator built with React.js. Inspired by http://codepen.io/tbremer/pen/wKpaWe

A Pen by HARUN PEHLÄ°VAN on CodePen.

License.