Recently I whipped up a handy VAT calculator. Not only that, I went further and created a website to house the calculator, with a view to adding even more calculators as and when needed.
Here's the finished: VAT calculator
Here's a roundup of all the main things I did to get this up and running from a dev perspective:
- Bootstrapped create-next-app
- Setup Typescript
- Created the Calculator component, which was built using smaller components
- Button
- Input
- Wrote the calculations for VAT, and then used in functions that calculate VAT either by deducting from Gross or adding to a Net figure
- Came up with some fairly rudimentary validation that checks to see if a string matches some regex (inputs convert values to strings)
- Deployed for free using Vercel
The reason I went this far is that it's a tech-stack I'm working with in my day-to-day job, you don't have to do all this setup, it's not necessary, I'm honing my skills in this area.
Here's the calculator code:
import React, { FC, useState, useRef } from 'react';
import Input from '../Input';
import Button from '../Button';
import style from './Calculator.module.css';
const Calculator: FC = () => {
const [amount, setAmount] = useState('0');
const [vatRate, setVatRate] = useState('20');
const getPercentage = Number(vatRate) / 100;
const correctPercentage = 1 + getPercentage;
const amountIncludingVat = Number(amount) * correctPercentage;
const amountExcludingVat = Number(amount) / correctPercentage;
const netRef = useRef(null);
const grossRef = useRef(null);
const twoDecimals = (unit): string => Number(unit).toFixed(2);
const validation = (unit, pattern): boolean => {
let valid = false;
if (typeof unit !== 'undefined' && typeof unit === 'string') {
valid = !!unit.match(pattern);
}
return valid;
};
const amountIsValid = validation(amount, /[0-9]/g) && amount !== '0';
const vatRateIsValid = validation(vatRate, /^\d+(.\d)?\d*$/g);
const validationRules = [amountIsValid, vatRateIsValid];
const scrollToResult = (result): void => {
const allTrue = validationRules.every((element) => {
return element === true;
});
if (allTrue) {
result.current.scrollIntoView({
behavior: 'smooth',
block: 'start',
});
}
};
return (
<>
<div className={style.andResults}>
<form className={style.root}>
<Input
labelText="Amount"
onChange={(e) => setAmount(e.target.value)}
id="amount"
type="number"
value={amount}
random
isValid={amountIsValid}
validationText="Please enter a number greater than 0"
/>
<Input
labelText="VAT Rate %"
onChange={(e) => setVatRate(e.target.value)}
id="vat-rate"
type="number"
value={vatRate}
isValid={vatRateIsValid}
validationText="Please enter a vat rate, e.g. 17.5"
/>
<div className={style.buttonWrapper}>
<Button onClick={() => scrollToResult(netRef)} importance="primary">
Add VAT
</Button>
<div className={style.buttonDivider}>Or</div>
<Button
onClick={() => scrollToResult(grossRef)}
importance="secondary"
>
Remove VAT
</Button>
</div>
</form>
<div ref={netRef} id="net-results" className={style.result}>
<h2>Results when adding vat</h2>
<Input
labelText="Net amount (excluding VAT)"
id="net-amount"
type="text"
value={twoDecimals(amount)}
readOnly
/>
<Input
labelText={`VAT at (${vatRate}%)`}
id="vat-rate-2"
type="text"
value={twoDecimals(amountIncludingVat - Number(amount))}
readOnly
/>
<Input
labelText="Gross amount (including VAT)"
id="gross-amount"
type="text"
value={twoDecimals(amountIncludingVat)}
readOnly
/>
</div>
<div ref={grossRef} id="gross-results" className={style.result}>
<h2>Results when removing vat</h2>
<Input
labelText="Gross amount (including VAT)"
id="gross-amount-2"
type="text"
value={twoDecimals(amount)}
readOnly
/>
<Input
labelText={`VAT at (${vatRate}%)`}
id="vat-rate-3"
type="text"
value={twoDecimals(Number(amount) - amountExcludingVat)}
readOnly
/>
<Input
labelText="Net amount (excluding VAT)"
id="net-amount-2"
type="text"
value={twoDecimals(amountExcludingVat)}
readOnly
/>
</div>
</div>
</>
);
};
export default Calculator;
Top comments (1)
Hey Morgan, your app looks amazing! Just a feedback, you might include radio buttons of VAT percentages. This is to save time when people are going to use your app multiple times in the day. Something like this one vat-calculator.uk
Cheers
Some comments have been hidden by the post's author - find out more