Inflation Calculator with React & TypeScript
Published: 2023-01-30 03:19:29

✨ [**Watch on YouTube**](https://youtu.be/U4OgjqaUcss)  |  🐙 [GitHub](https://github.com/RodionChachura/inflation)  |  🎮 [Demo](https://inflation-radzionchachura.vercel.app/)

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.png)

To set up the app, I utilize Next.js and components from the [react-toolkit repository](https://github.com/RodionChachura/react-toolkit) 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.

```tsx
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`.

```ts
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.