problem statement: using React and Redux build an interest calculator that, given a principal, rate of annual interest, and number of years, will display the total principal plus interest using the formula
TOTAL = principal * (1 + (rate * years))
Any feedback welcome on the style, approach, etc.
<!doctype html>
<html><body>
<section></section>
<script src="https://unpkg.com/react/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/redux"></script>
<script src="https://unpkg.com/react-redux"></script>
<script src="https://unpkg.com/htm"></script>
<script>
const jsx = htm.bind(React.createElement);
function reducer(model={
total: 0,
}, action={type:'', payload: null}){
let store;
switch(action.type){
case 'TOTAL_COST':
store = { total: action.payload.total };
break;
default:
store = model;
}
return store;
}
const actions = {
updateTotal: function({ principal, years, rate }){
return {
type: 'TOTAL_COST',
payload: {total: principal * (1 + (rate * years))}
}
}
};
const store = Redux.createStore(reducer);
class App extends React.Component{
constructor(props){
super(props);
this.state = {
principal: 1000,
years: 7,
rate: 0.025
};
this.submit = this.submit.bind(this);
this.update = this.update.bind(this);
}
componentWillMount(){
this.submit(new CustomEvent('init'));
}
update(e){
//const val = e.target.value * 1;
let { valueAsNumber, value, name } = e.target;
const state = {...this.state};
if(isNaN(valueAsNumber)){
valueAsNumber = 0;
}
state[ name ] = valueAsNumber;
this.props.dispatch( actions.updateTotal(state) );
this.setState({[name]: valueAsNumber});
}
submit(e){
e.preventDefault();
this.props.dispatch( actions.updateTotal(this.state) );
}
//TOTAL = principal * (1 + (rate * years))
render(){
const { principal, years, rate } = this.state;
return jsx`<form onSubmit=${ this.submit }>
<style>
label{display:block;}
</style>
<h2>interest calculator</h2>
<h1><label> total <span>${ this.props.total.toFixed(2) }</span> </label></h1>
<fieldset>
<label> principal <input name=principal onInput=${ this.update } type="number" min=1 defaultValue=${ principal } /> </label>
<label> years <input name=years onInput=${ this.update }type="number" min=1 max=300 defaultValue=${ years } /> </label>
<label> rate <input name=rate onInput=${ this.update } type="number" min=0 max=100 defaultValue=${ rate } step=0.0001 /> </label>
</fieldset>
<button>calculate</button>
</form>`;
}
}
const ConnectedApp = ReactRedux.connect((store)=>{return {total:store.total}})(App);
ReactDOM.render(
jsx`<${ReactRedux.Provider} store=${ store }> <${ ConnectedApp } key=${ Date.now() }> <//> <//>`,
document.querySelector('section')
);
requestAnimationFrame(()=>{
console.log(`🚀 tests running → any failures will be shown below`);
requestAnimationFrame(()=>{ console.log(`🍻 tests done → any failures are shown above`); });
const { updateTotal } = actions;
let result = updateTotal({principal: 5000, years: 5, rate: 0.025}).payload;
let expected = 5625;
console.assert(Math.round(result.total) === expected, `expected total ${ result.total } to be ${ expected }`, result);
});
</script>