Inflation Calculator with React & TypeScript

January 18, 2023

3 min read

Inflation Calculator with React & TypeScript
Watch on YouTube

Let's develop a straightforward application that illustrates the amount of money you are losing due to inflation. Inflation is currently substantial, and this app will serve as an incentive to take action with your money.

demo

To set up the app, I utilize Next.js and components from the radzionkit repository repository, which I typically copy to begin a new project. I prefer having most of the components in the codebase, so that I can directly make the necessary changes, rather than dealing with complex frameworks.

We begin by including the title and description in the head for SEO purposes. The root container will be a flexbox element with some padding and center alignment. The content will be inside another flexbox element with a maximum width and a gap between each element. By using the VStack/HStack components, we rarely need to use the margin attribute.

import { InflationReport } from "components/InflationReport"
import { InflationResourcePromotion } from "components/InflationResourcePromotion"
import { DollarIcon } from "lib/ui/icons/DollarIcon"
import { PercentIcon } from "lib/ui/icons/PercentIcon"
import { AmountTextInput } from "lib/ui/inputs/AmountTextInput"
import { VStack } from "lib/ui/Stack"
import { Text } from "lib/ui/Text"
import Head from "next/head"
import { useState } from "react"
import styled from "styled-components"

const Container = styled(VStack)`
  padding: 80px 20px 40px 20px;

  align-items: center;
`

const Content = styled(VStack)`
  max-width: 360px;
  gap: 20px;
`

export default function Home() {
  const [amount, setAmount] = useState<number | undefined>(100000)
  const [inflation, setInflation] = useState<number | undefined>(8)

  return (
    <>
      <Head>
        <title>Inflation Calculator | See how your savings lose value</title>
        <meta
          name="description"
          content="Calculate how much money you lose to inflation every year/month/day"
        />
      </Head>
      <Container>
        <Content>
          <Text
            style={{ textTransform: "uppercase" }}
            weight="semibold"
            as="h1"
          >
            How much do I lose to{" "}
            <Text as="span" color="alert">
              inflation?
            </Text>
          </Text>
          <VStack gap={4}>
            <AmountTextInput
              label="Savings"
              value={amount}
              onValueChange={setAmount}
              shouldBePositive
              shouldBeInteger
              unit={<DollarIcon />}
            />
            <AmountTextInput
              label="Inflation"
              value={inflation}
              onValueChange={setInflation}
              shouldBePositive
              unit={<PercentIcon />}
            />
          </VStack>
          {amount !== undefined && inflation !== undefined && (
            <InflationReport savings={amount} inflation={inflation} />
          )}
          <InflationResourcePromotion />
        </Content>
      </Container>
    </>
  )
}

For both amount and inflation fields we use the same AmountTextInput component. It shows a unit of the input value at the beginning to make it's more intuitive for the user.

If both inputs contain valid values, we render the InflationReport component, which receives the amount and inflation values as props and displays basic calculations about the money lost due to inflation. To format the currency, we use Intl.NumberFormat.

const sharedFormatterConfig = {
  style: "currency",
  currency: "USD",
}

const intCurrencyFormatter = new Intl.NumberFormat("en-US", {
  ...sharedFormatterConfig,
  maximumFractionDigits: 0,
  minimumFractionDigits: 0,
})

const floatCurrencyFormatter = new Intl.NumberFormat("en-US", {
  ...sharedFormatterConfig,
  maximumFractionDigits: 2,
})

export const formatCurrencyAmount = (amount: number) => {
  const formatter = Number.isInteger(amount)
    ? intCurrencyFormatter
    : floatCurrencyFormatter

  return formatter.format(amount)
}

Lastly, we display the InflationResourcePromotion component, which serves as a call to action to watch a video on YouTube with some investment ideas.