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