Building a React Finance Calculator

29/10/18

Not written a blog for a while, so I thought I would right about a relatively interesting component I built recently.

A client I was working with asked about the possibility of getting a finance calculator on his page and at first I was going to push back due to me believing I didn't really have time. But then I thought about it and decided it couldn't take THAT long and would be an excellent learning opportunity.

I have an improving understanding of React JS now, so with an idea in my head, and armed with Stack overflow open in another window I set off building it!

Without going into massive detail about the project, I had a 'product page' and on there I placed a button for finance options. I wanted this to pop out into a modal where the finance calculator widget would be held. I will hold my hands up and admit that I didn't build the modal myself. I used react-modal. It worked perfectly for what I wanted it for and saved me a bit of time.

Once the modal was sorted I set about setting up my inputs. I needed 4 bits of information. Product price, term of finance, deposit and warranty period. The product price was easily passed down to the component as a prop, so that was simple. The term of the finance could be between 1 and 5 years. I thought about this and I believed my best option would be to use a slider something like this...

Slider with marks

Again, I new that there would be something out there and reinventing the wheel is generally something I don't do! So I found RC-Slider and got this imported into the project. The documentation was good and I was able to quickly get it behaving how I wanted it to behave. I also added a couple of custom styles to get it looking more in keeping with my colour scheme. The slider aslo had a handy 'onAfterChange' prop which you can pass a function into, which I needed a bit later.

.rc-slider {
  .rc-slider-track {
    background-color: #333333;
  }
  .rc-slider-handle {
    border: solid 2px #f6b05d;

    &:hover {
      border-color: #333333;
    }
  }

  .rc-slider-dot-active {
    border-color: #333333;
  }
}

.rc-slider-mark-text {
  font-family: 'Roboto';
  font-size: 1rem;
  color: #333333;
}
import Slider from 'rc-slider'

const customStyles = {
  content: {
    top: '50%',
    left: '50%',
    transform: 'translate(-50%, -50%)',
    width: '95%',
    height: '95%',
    maxWidth: '670px',
    maxHeight: '670px',
  },
}

const marks = {
  1: '12',
  2: '24',
  3: '36',
  4: '48',
  5: '60',
}

<div className="slider-container">
  <h3 className="finance-subheader">
    Term (Months)
  </h3>
  <Slider
    min={1}
    max={5}
    marks={marks}
    onAfterChange={this.handleSliderChange}
  />
</div>

Giving the end result of...

Slider with marks

So I had my original price, grabbed the deposit and the warranty term from the input using an onchange event and setting the input value to state using a small function...

handleChange(e) {
    const name = e.target.name
    this.setState({
      [name]: e.target.value,
    })
}

I had to write a slightly different function for grabbing the term from the slider above due to the 'onAfterChange' prop returning which mark it was currently at. This was easy enough to deal with though as I could just multiply the number by 12 to get my term in months.

Next I needed to do some maths. I am ok at maths, but working out finance, I couldn't really be bothered thinking about it at 7:30pm! I found this simple finance calculator which did the maths for you but explained what is was doing and why. So using this I was able to construct the following function to handle my calculations...

  generatePricePerMonth(deposit, warranty, term, price) {
    function calculatePrices(origPrice) {
      let actualPrice = origPrice - deposit
      let priceWithInterest = actualPrice * (1 + APR * term)
      let interest = priceWithInterest - actualPrice
      let monthlyPayments = priceWithInterest / (term * 12)
      return {
        monthlyPayments: Math.round(monthlyPayments * 100) / 100,
        interest: Math.round(interest * 100) / 100,
        priceWithInterest: Math.round(priceWithInterest * 100) / 100,
        term: term * 12,
        price: origPrice,
      }
    }
    deposit = parseInt(deposit)
    const APR = 0.099
    let basePrice = price
    if (warranty === '5') {
      return calculatePrices(basePrice)
    } else if (warranty === '10') {
      return calculatePrices(basePrice)
    }
  }

It works well. I checked it against the online calculator and everything seemed in order. The final result looks like this...

Final Finance Calculator

I was pleased with the final result as I was doubting as to whether I would be able to do this, and I surprised myself with not only the outcome but with how quickly I was able to do it and also with minimal googling. Simple reading the documentation and using my own knowledge. Please tweet me at @jonesovic if you have any comments on the code or any improvements I can make!

Thanks