Working With Currency, Better

Daily Standup

I’ve still been working on project GFT (surprise!) and most recently worked on improving how I handle currency in the app.

Strings - NO

Initially I did the quick and dirty way: just have the user input be a string, and the user can add in whatever currency symbol they want, or omit it all together. This is not ideal because:

  • No consistency between users
  • Can’t perform calculations on the amounts, which is on the roadmap

But I finally fixed it.

Two columns instead of one

First it required setting up two new fields in the table where the prices would be stored: one for the price in cents, and the other for the currency.

The ideal scenario would be to reference the currency codes from another table of allowed currencies. This would also let me loop through the currency options on the front end more simply. I opted not to do this for now—I don’t want a crazy-long list of mostly irrelevant currencies in the app right now, and it was also faster just to use strings. However, now I’m generating the strings for the user so there will be consistency at least.

Why in cents?

JavaScript does some weird things when calculating decimal numbers, so it’s best instead to store in cents, and then do the calculation to dollars/euros/etc just for the views. In fact it can be managed by a tidy little helper function:

const formatPrice = (cents, currencyCode) => {
return (cents / 100).toLocaleString(['en-US'], {
style: 'currency',
currency: currencyCode,
});
};

That locale (en-US) is an array that can be extended to include more locales as needed.

The calculation goes the other way to, to format the number before it goes into the database:

const priceInCents = parseFloat(req.body.priceInCents).toFixed(2) * 100;

Not to be forgotten: the price_in_cents field in the database has validation to only allow an integer.

Not Perfect

One thing I didn’t like is that if you have an edit form, you can’t always properly display an existing price in an editable input field: if the price is £32.50, it will drop the trailing zero and display 32.5. I did find one way potentially to make it display in the way you’d expect using JavaScript. Maybe I’ll address this one day, for now I’ve decided to leave it.

Overall, Not Too Bad

Overall, this implementation took about 90 minutes to switch over from strings to numbers, and most of that was spent fuddling around in the views and making sure all of the relevant files got the updates they needed. I probably should have set it up like this in the first place!

Other Stuff

Discovered unDraw, a source for rights-cleared sketches…cool! Will be adding these to the project. Here’s a relevant example of what they look like:

Money and computers working well together

Up Next

Adding pagination or lazy loading, now that I’m up to displaying 903 cards on a primary page in the site 😬