Compare commits
5 Commits
64669e5f58
...
acec849428
Author | SHA1 | Date | |
---|---|---|---|
acec849428 | |||
1e9f2cbc2d | |||
9c460bab22 | |||
4e7705ce53 | |||
d5962bbf9e |
15
package-lock.json
generated
15
package-lock.json
generated
@ -17,6 +17,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.503.0",
|
"lucide-react": "^0.503.0",
|
||||||
"next": "^15.2.3",
|
"next": "^15.2.3",
|
||||||
|
"next-plausible": "^3.12.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-hook-form": "^7.56.1",
|
"react-hook-form": "^7.56.1",
|
||||||
@ -5089,6 +5090,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/next-plausible": {
|
||||||
|
"version": "3.12.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/next-plausible/-/next-plausible-3.12.4.tgz",
|
||||||
|
"integrity": "sha512-cD3+ixJxf8yBYvsideTxqli3fvrB7R4BXcvsNJz8Sm2X1QN039WfiXjCyNWkub4h5++rRs6fHhchUMnOuJokcg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/4lejandrito/next-plausible?sponsor=1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"next": "^11.1.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 ",
|
||||||
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/next/node_modules/postcss": {
|
"node_modules/next/node_modules/postcss": {
|
||||||
"version": "8.4.31",
|
"version": "8.4.31",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"lucide-react": "^0.503.0",
|
"lucide-react": "^0.503.0",
|
||||||
"next": "^15.2.3",
|
"next": "^15.2.3",
|
||||||
|
"next-plausible": "^3.12.4",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-hook-form": "^7.56.1",
|
"react-hook-form": "^7.56.1",
|
||||||
|
@ -507,7 +507,7 @@ export default function FireCalculatorForm() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{result && result.yearlyData && result.yearlyData.length > 0 && (
|
{result.yearlyData && result.yearlyData.length > 0 && (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Financial Projection</CardTitle>
|
<CardTitle>Financial Projection</CardTitle>
|
||||||
@ -549,7 +549,7 @@ export default function FireCalculatorForm() {
|
|||||||
} else if (value >= 1000) {
|
} else if (value >= 1000) {
|
||||||
return `${(value / 1000).toFixed(0)}K`;
|
return `${(value / 1000).toFixed(0)}K`;
|
||||||
}
|
}
|
||||||
return `${value}`;
|
return value.toString();
|
||||||
}}
|
}}
|
||||||
width={80}
|
width={80}
|
||||||
/>
|
/>
|
||||||
@ -560,7 +560,7 @@ export default function FireCalculatorForm() {
|
|||||||
.payload as (typeof result.yearlyData)[0];
|
.payload as (typeof result.yearlyData)[0];
|
||||||
return (
|
return (
|
||||||
<div className="bg-background border p-2 shadow-sm">
|
<div className="bg-background border p-2 shadow-sm">
|
||||||
<p className="font-medium">{`Year: ${data.year} (Age: ${data.age})`}</p>
|
<p className="font-medium">{`Year: ${data.year.toString()} (Age: ${data.age.toString()})`}</p>
|
||||||
<p className="text-primary">{`Balance: ${formatNumber(data.balance)}`}</p>
|
<p className="text-primary">{`Balance: ${formatNumber(data.balance)}`}</p>
|
||||||
{result.fireNumber && (
|
{result.fireNumber && (
|
||||||
<p className="text-destructive">{`FIRE Number: ${formatNumber(result.fireNumber)}`}</p>
|
<p className="text-destructive">{`FIRE Number: ${formatNumber(result.fireNumber)}`}</p>
|
||||||
|
77
src/app/components/web-vitals.tsx
Normal file
77
src/app/components/web-vitals.tsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { usePlausible } from "next-plausible";
|
||||||
|
import { useReportWebVitals } from "next/web-vitals";
|
||||||
|
interface Metric {
|
||||||
|
/**
|
||||||
|
* The name of the metric (in acronym form).
|
||||||
|
*/
|
||||||
|
name: "CLS" | "FCP" | "FID" | "INP" | "LCP" | "TTFB";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current value of the metric.
|
||||||
|
*/
|
||||||
|
value: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rating as to whether the metric value is within the "good",
|
||||||
|
* "needs improvement", or "poor" thresholds of the metric.
|
||||||
|
*/
|
||||||
|
rating: "good" | "needs-improvement" | "poor";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The delta between the current value and the last-reported value.
|
||||||
|
* On the first report, `delta` and `value` will always be the same.
|
||||||
|
*/
|
||||||
|
delta: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique ID representing this particular metric instance. This ID can
|
||||||
|
* be used by an analytics tool to dedupe multiple values sent for the same
|
||||||
|
* metric instance, or to group multiple deltas together and calculate a
|
||||||
|
* total. It can also be used to differentiate multiple different metric
|
||||||
|
* instances sent from the same page, which can happen if the page is
|
||||||
|
* restored from the back/forward cache (in that case new metrics object
|
||||||
|
* get created).
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any performance entries relevant to the metric value calculation.
|
||||||
|
* The array may also be empty if the metric value was not based on any
|
||||||
|
* entries (e.g. a CLS value of 0 given no layout shifts).
|
||||||
|
*/
|
||||||
|
entries: PerformanceEntry[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of navigation.
|
||||||
|
*
|
||||||
|
* This will be the value returned by the Navigation Timing API (or
|
||||||
|
* `undefined` if the browser doesn't support that API), with the following
|
||||||
|
* exceptions:
|
||||||
|
* - 'back-forward-cache': for pages that are restored from the bfcache.
|
||||||
|
* - 'back_forward' is renamed to 'back-forward' for consistency.
|
||||||
|
* - 'prerender': for pages that were prerendered.
|
||||||
|
* - 'restore': for pages that were discarded by the browser and then
|
||||||
|
* restored by the user.
|
||||||
|
*/
|
||||||
|
navigationType:
|
||||||
|
| "navigate"
|
||||||
|
| "reload"
|
||||||
|
| "back-forward"
|
||||||
|
| "back-forward-cache"
|
||||||
|
| "prerender"
|
||||||
|
| "restore";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebVitals() {
|
||||||
|
const plausible = usePlausible();
|
||||||
|
useReportWebVitals((metric: Metric) => {
|
||||||
|
plausible("web-vitals", {
|
||||||
|
props: {
|
||||||
|
[metric.name]: metric.rating,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return <></>;
|
||||||
|
}
|
@ -1,13 +1,14 @@
|
|||||||
import "@/styles/globals.css";
|
import "@/styles/globals.css";
|
||||||
|
import PlausibleProvider from "next-plausible";
|
||||||
import { type Metadata } from "next";
|
import { type Metadata } from "next";
|
||||||
import { Geist } from "next/font/google";
|
import { Geist } from "next/font/google";
|
||||||
|
import { WebVitals } from "./components/web-vitals";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title:
|
title:
|
||||||
"FIRE Calculator - Plan Your Financial Independence & Early Retirement",
|
"InvestingFIRE Calculator | Plan Your Financial Independence & Early Retirement",
|
||||||
description:
|
description:
|
||||||
"Calculate your FIRE number, estimate your retirement age, and plan your path to financial independence with this comprehensive FIRE calculator.",
|
"Achieve Financial Independence, Retire Early (FIRE) with the InvestingFIRE calculator. Get personalized projections and investing advice to plan your journey.",
|
||||||
icons: [{ rel: "icon", url: "/favicon.ico" }],
|
icons: [{ rel: "icon", url: "/favicon.ico" }],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,7 +22,16 @@ export default function RootLayout({
|
|||||||
}: Readonly<{ children: React.ReactNode }>) {
|
}: Readonly<{ children: React.ReactNode }>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" className={geist.variable}>
|
<html lang="en" className={geist.variable}>
|
||||||
<body>{children}</body>
|
<PlausibleProvider
|
||||||
|
domain="investingfire.com"
|
||||||
|
customDomain="https://analytics.schulze.network"
|
||||||
|
selfHosted={true}
|
||||||
|
enabled={true}
|
||||||
|
trackOutboundLinks={true}
|
||||||
|
>
|
||||||
|
<WebVitals />
|
||||||
|
<body>{children}</body>
|
||||||
|
</PlausibleProvider>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
156
src/app/page.tsx
156
src/app/page.tsx
@ -9,41 +9,54 @@ import {
|
|||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
return (
|
return (
|
||||||
<main className="text-primary-foreground to-destructive from-secondary flex min-h-screen flex-col items-center bg-gradient-to-b p-4">
|
<main className="text-primary-foreground to-destructive from-secondary flex min-h-screen flex-col items-center bg-gradient-to-b p-4">
|
||||||
<div className="container mx-auto flex flex-col items-center justify-center gap-12 px-4 py-16">
|
<div className="container mx-auto flex flex-col items-center justify-center gap-4 px-4 py-16 text-center">
|
||||||
<h1 className="text-primary-foreground text-5xl font-extrabold tracking-tight sm:text-[5rem]">
|
<h1 className="from-primary via-primary-foreground to-primary bg-gradient-to-r bg-clip-text text-5xl font-extrabold tracking-tight text-transparent drop-shadow-md sm:text-[5rem]">
|
||||||
FIRE Calculator
|
InvestingFIRE
|
||||||
</h1>
|
</h1>
|
||||||
<FireCalculatorForm />
|
<p className="text-primary-foreground/90 text-xl font-semibold md:text-2xl">
|
||||||
|
The #1 FIRE Calculator
|
||||||
|
</p>
|
||||||
|
<div className="mt-8 w-full max-w-2xl">
|
||||||
|
<FireCalculatorForm />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Added SEO Content Sections */}
|
{/* Added SEO Content Sections */}
|
||||||
<div className="container mx-auto max-w-4xl px-4 py-8 text-left">
|
<div className="container mx-auto max-w-4xl px-4 py-8 text-left">
|
||||||
<section className="mb-12">
|
<section className="mb-12">
|
||||||
<h2 className="mb-4 text-3xl font-bold">What is FIRE?</h2>
|
<h2 className="mb-4 text-3xl font-bold">
|
||||||
|
What is FIRE? Understanding Financial Independence and Early
|
||||||
|
Retirement
|
||||||
|
</h2>
|
||||||
<p className="mb-4 text-lg leading-relaxed">
|
<p className="mb-4 text-lg leading-relaxed">
|
||||||
FIRE stands for "Financial Independence, Retire Early."
|
FIRE stands for "Financial Independence, Retire Early."
|
||||||
It's a movement focused on aggressive saving and investing to
|
It's a movement focused on aggressive saving and strategic
|
||||||
build a large enough portfolio that the returns can cover living
|
investing to build a substantial portfolio. The goal is for
|
||||||
expenses indefinitely. Achieving FIRE means you are no longer
|
investment returns to cover living expenses indefinitely, freeing
|
||||||
dependent on traditional employment to fund your lifestyle, giving
|
you from traditional employment. Achieving FIRE means gaining the
|
||||||
you the freedom to pursue passions, travel, or simply enjoy life
|
freedom to pursue passions, travel, or simply enjoy life without
|
||||||
without the need for a regular paycheck.
|
needing a regular paycheck. Sound investing advice is crucial for
|
||||||
|
building the wealth needed.
|
||||||
</p>
|
</p>
|
||||||
<p className="text-lg leading-relaxed">
|
<p className="text-lg leading-relaxed">
|
||||||
The core principle often involves saving a high percentage of income
|
The core principle involves maximizing your savings rate (often
|
||||||
(sometimes 50% or more) and investing it wisely, typically in
|
50%+) and investing wisely, typically in low-cost, diversified
|
||||||
low-cost index funds. The target amount, often called the "FIRE
|
assets like index funds. Your "FIRE number" – the capital
|
||||||
number," is usually calculated as 25 times your desired annual
|
needed – is often estimated as 25 times your desired annual
|
||||||
spending, based on the 4% safe withdrawal rate rule.
|
spending, derived from the 4% safe withdrawal rate guideline. This
|
||||||
|
FIRE calculator helps you personalize this estimate.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mb-12">
|
<section className="mb-12">
|
||||||
<h2 className="mb-4 text-3xl font-bold">How This Calculator Works</h2>
|
<h2 className="mb-4 text-3xl font-bold">
|
||||||
|
How This FIRE Calculator Provides Investing Insights
|
||||||
|
</h2>
|
||||||
<p className="mb-4 text-lg leading-relaxed">
|
<p className="mb-4 text-lg leading-relaxed">
|
||||||
This calculator helps you estimate your path to FIRE based on your
|
This calculator helps visualize your path to FIRE by projecting
|
||||||
current financial situation and future projections. Here's a
|
investment growth based on your inputs. Understanding these
|
||||||
breakdown of the inputs:
|
projections is a key piece of investing advice for long-term
|
||||||
|
planning. Here's a breakdown of the inputs:
|
||||||
</p>
|
</p>
|
||||||
<ul className="mb-4 ml-6 list-disc space-y-2 text-lg">
|
<ul className="mb-4 ml-6 list-disc space-y-2 text-lg">
|
||||||
<li>
|
<li>
|
||||||
@ -78,19 +91,19 @@ export default function HomePage() {
|
|||||||
</ul>
|
</ul>
|
||||||
<p className="text-lg leading-relaxed">
|
<p className="text-lg leading-relaxed">
|
||||||
The calculator simulates your investment growth year by year,
|
The calculator simulates your investment growth year by year,
|
||||||
factoring in monthly contributions, compound growth, and
|
incorporating monthly contributions, the power of compound growth (a
|
||||||
inflation's effect on your target allowance. It then determines
|
core investing principle), and inflation's impact on your
|
||||||
the age at which your accumulated capital is sufficient to sustain
|
target allowance. It estimates the age at which your capital could
|
||||||
your desired, inflation-adjusted monthly allowance throughout your
|
sustain your desired, inflation-adjusted monthly spending throughout
|
||||||
expected retirement years until your specified life expectancy. It
|
your expected retirement until your specified life expectancy. It
|
||||||
estimates your "FIRE Number" (the capital needed at
|
calculates your potential "FIRE Number" and the age you
|
||||||
retirement) and the age you might reach it.
|
might reach financial independence.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="mb-12">
|
<section className="mb-12">
|
||||||
<h2 className="mb-4 text-3xl font-bold">
|
<h2 className="mb-4 text-3xl font-bold">
|
||||||
Frequently Asked Questions (FAQ)
|
FIRE & Investing Frequently Asked Questions (FAQ)
|
||||||
</h2>
|
</h2>
|
||||||
<Accordion type="single" collapsible className="w-full">
|
<Accordion type="single" collapsible className="w-full">
|
||||||
<AccordionItem value="item-1">
|
<AccordionItem value="item-1">
|
||||||
@ -110,15 +123,16 @@ export default function HomePage() {
|
|||||||
|
|
||||||
<AccordionItem value="item-2">
|
<AccordionItem value="item-2">
|
||||||
<AccordionTrigger className="text-xl font-semibold">
|
<AccordionTrigger className="text-xl font-semibold">
|
||||||
Is the Expected Growth Rate realistic?
|
Is the Expected Growth Rate realistic? Finding the right
|
||||||
|
investing advice often starts here.
|
||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
<AccordionContent className="text-lg leading-relaxed">
|
<AccordionContent className="text-lg leading-relaxed">
|
||||||
Historically, diversified stock market investments have returned
|
Historically, diversified stock market investments have returned
|
||||||
around 7-10% annually over the long term, before inflation. A
|
around 7-10% annually long-term (before inflation). A rate of 7%
|
||||||
rate of 7% (after fees) is often used as a reasonable estimate,
|
(after fees) is common, but remember past performance
|
||||||
but past performance doesn't guarantee future results.
|
doesn't guarantee future results, a fundamental piece of
|
||||||
It's crucial to choose a rate you feel comfortable with and
|
investing advice. Choose a rate reflecting your risk tolerance
|
||||||
understand the associated risks.
|
and investment strategy.
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
|
|
||||||
@ -138,15 +152,15 @@ export default function HomePage() {
|
|||||||
|
|
||||||
<AccordionItem value="item-4">
|
<AccordionItem value="item-4">
|
||||||
<AccordionTrigger className="text-xl font-semibold">
|
<AccordionTrigger className="text-xl font-semibold">
|
||||||
Can I really retire early?
|
Can I really retire early with FIRE?
|
||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
<AccordionContent className="text-lg leading-relaxed">
|
<AccordionContent className="text-lg leading-relaxed">
|
||||||
Retiring significantly earlier than traditional retirement age
|
Retiring significantly early is achievable but demands
|
||||||
is possible but requires discipline, a high savings rate, and
|
discipline, a high savings rate, and smart investing. Success
|
||||||
consistent investment growth. The feasibility depends heavily on
|
depends on income, expenses, savings habits, and investment
|
||||||
your income, expenses, savings habits, and investment returns.
|
returns. Use this FIRE calculator as a planning tool,
|
||||||
Use this calculator as a tool for planning and motivation, but
|
understanding it provides estimates based on your assumptions
|
||||||
remember it provides estimates based on your inputs.
|
and chosen investing approach.
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
|
|
||||||
@ -182,26 +196,24 @@ export default function HomePage() {
|
|||||||
{/* Optional: Add a section for relevant resources/links here */}
|
{/* Optional: Add a section for relevant resources/links here */}
|
||||||
<section className="mb-12">
|
<section className="mb-12">
|
||||||
<h2 className="mb-4 text-3xl font-bold">
|
<h2 className="mb-4 text-3xl font-bold">
|
||||||
Further Reading & Resources
|
FIRE Journey & Investing Resources
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mb-6 text-lg leading-relaxed">
|
<p className="mb-6 text-lg leading-relaxed">
|
||||||
Want to learn more about FIRE and continue your journey to financial
|
Ready to dive deeper into FIRE and solidify your investing strategy?
|
||||||
independence? Here are some valuable resources to explore:
|
Explore these valuable resources for financial independence planning
|
||||||
|
and investing advice:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="bg-secondary/20 my-8 rounded-md p-4 text-lg">
|
<div className="bg-secondary/20 my-8 rounded-md p-4 text-lg">
|
||||||
<p className="font-semibold">Getting Started with FIRE:</p>
|
<p className="font-semibold">Getting Started with FIRE:</p>
|
||||||
<ol className="ml-6 list-decimal space-y-1">
|
<ol className="ml-6 list-decimal space-y-1">
|
||||||
<li>
|
<li>
|
||||||
Read foundational content like Mr. Money Mustache's simple
|
Calculate your personal numbers using this FIRE calculator and
|
||||||
math article
|
other tools.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Calculate your personal numbers using this and other FIRE
|
Seek sound investing advice and consider joining communities
|
||||||
calculators
|
like r/Fire for support.
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Join communities like r/Fire to ask questions and find support
|
|
||||||
</li>
|
</li>
|
||||||
<li>Explore books and podcasts to deepen your understanding</li>
|
<li>Explore books and podcasts to deepen your understanding</li>
|
||||||
</ol>
|
</ol>
|
||||||
@ -209,24 +221,24 @@ export default function HomePage() {
|
|||||||
|
|
||||||
<div className="grid gap-8 md:grid-cols-2">
|
<div className="grid gap-8 md:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="mb-3 text-xl font-semibold">Blogs & Websites</h3>
|
<h3 className="mb-3 text-xl font-semibold">
|
||||||
|
Blogs & Investing Websites
|
||||||
|
</h3>
|
||||||
<ul className="ml-6 list-disc space-y-2 text-lg">
|
<ul className="ml-6 list-disc space-y-2 text-lg">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://www.mrmoneymustache.com/2012/01/13/the-shockingly-simple-math-behind-early-retirement/"
|
href="https://www.mrmoneymustache.com/2012/01/13/the-shockingly-simple-math-behind-early-retirement/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
Mr. Money Mustache - The Shockingly Simple Math Behind Early
|
Mr. Money Mustache - Simple Math Behind Early Retirement &
|
||||||
Retirement
|
Investing
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://www.playingwithfire.co/resources"
|
href="https://www.playingwithfire.co/resources"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
Playing With FIRE - Comprehensive Resources
|
Playing With FIRE - Comprehensive Resources
|
||||||
@ -236,7 +248,6 @@ export default function HomePage() {
|
|||||||
<a
|
<a
|
||||||
href="https://www.reddit.com/r/Fire/"
|
href="https://www.reddit.com/r/Fire/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
r/Fire Reddit Community
|
r/Fire Reddit Community
|
||||||
@ -246,23 +257,24 @@ export default function HomePage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="mb-3 text-xl font-semibold">Books & Learning</h3>
|
<h3 className="mb-3 text-xl font-semibold">
|
||||||
|
Books & Investment Learning
|
||||||
|
</h3>
|
||||||
<ul className="ml-6 list-disc space-y-2 text-lg">
|
<ul className="ml-6 list-disc space-y-2 text-lg">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://www.amazon.com/Your-Money-Life-Transforming-Relationship/dp/0143115766"
|
href="https://www.amazon.com/Your-Money-Life-Transforming-Relationship/dp/0143115766"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
Your Money or Your Life - Vicki Robin & Joe Dominguez
|
Your Money or Your Life - Foundational FIRE & Investing
|
||||||
|
Principles
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://www.playingwithfire.co/"
|
href="https://www.playingwithfire.co/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
Playing With FIRE Documentary
|
Playing With FIRE Documentary
|
||||||
@ -272,10 +284,10 @@ export default function HomePage() {
|
|||||||
<a
|
<a
|
||||||
href="https://podcasts.apple.com/us/podcast/can-you-retire-now-this-fire-calculator-will-tell-you/id1330225136?i=1000683436292"
|
href="https://podcasts.apple.com/us/podcast/can-you-retire-now-this-fire-calculator-will-tell-you/id1330225136?i=1000683436292"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
BiggerPockets Money Podcast - FIRE Calculators
|
BiggerPockets Money Podcast - FIRE Calculators & Investing
|
||||||
|
Strategies
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -283,14 +295,13 @@ export default function HomePage() {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="mb-3 text-xl font-semibold">
|
<h3 className="mb-3 text-xl font-semibold">
|
||||||
Additional Calculators & Tools
|
Additional FIRE & Investing Calculators
|
||||||
</h3>
|
</h3>
|
||||||
<ul className="ml-6 list-disc space-y-2 text-lg">
|
<ul className="ml-6 list-disc space-y-2 text-lg">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://walletburst.com/tools/coast-fire-calculator/"
|
href="https://walletburst.com/tools/coast-fire-calculator/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
Coast FIRE Calculator - For those considering a partial
|
Coast FIRE Calculator - For those considering a partial
|
||||||
@ -301,26 +312,34 @@ export default function HomePage() {
|
|||||||
<a
|
<a
|
||||||
href="https://www.empower.com/retirement-calculator"
|
href="https://www.empower.com/retirement-calculator"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
Empower Retirement Planner - Free portfolio analysis and net
|
Empower Retirement Planner - Free portfolio analysis and net
|
||||||
worth tracking
|
worth tracking
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="https://www.investor.gov/financial-tools-calculators/calculators/compound-interest-calculator"
|
||||||
|
target="_blank"
|
||||||
|
className="text-primary hover:underline"
|
||||||
|
>
|
||||||
|
CAGR Compound Interest Calculator - Understand Investment
|
||||||
|
Growth
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="mb-3 text-xl font-semibold">
|
<h3 className="mb-3 text-xl font-semibold">
|
||||||
Recent Articles & Trends
|
Recent Investing & FIRE Articles
|
||||||
</h3>
|
</h3>
|
||||||
<ul className="ml-6 list-disc space-y-2 text-lg">
|
<ul className="ml-6 list-disc space-y-2 text-lg">
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href="https://www.businessinsider.com/retiring-tech-early-coast-fire-make-me-millionaire-2025-4"
|
href="https://www.businessinsider.com/retiring-tech-early-coast-fire-make-me-millionaire-2025-4"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
Coast FIRE: Retiring in your 30s while becoming a
|
Coast FIRE: Retiring in your 30s while becoming a
|
||||||
@ -331,7 +350,6 @@ export default function HomePage() {
|
|||||||
<a
|
<a
|
||||||
href="https://www.businessinsider.com/financial-independence-retire-early-saving-loneliness-retreat-bali-making-friends-2025-2"
|
href="https://www.businessinsider.com/financial-independence-retire-early-saving-loneliness-retreat-bali-making-friends-2025-2"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="text-primary hover:underline"
|
className="text-primary hover:underline"
|
||||||
>
|
>
|
||||||
The Social Side of FIRE: Finding Community in Financial
|
The Social Side of FIRE: Finding Community in Financial
|
||||||
|
40
src/env.js
Normal file
40
src/env.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { createEnv } from "@t3-oss/env-nextjs";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const env = createEnv({
|
||||||
|
/**
|
||||||
|
* Specify your server-side environment variables schema here. This way you can ensure the app
|
||||||
|
* isn't built with invalid env vars.
|
||||||
|
*/
|
||||||
|
server: {
|
||||||
|
NODE_ENV: z.enum(["development", "test", "production"]),
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify your client-side environment variables schema here. This way you can ensure the app
|
||||||
|
* isn't built with invalid env vars. To expose them to the client, prefix them with
|
||||||
|
* `NEXT_PUBLIC_`.
|
||||||
|
*/
|
||||||
|
client: {
|
||||||
|
// NEXT_PUBLIC_CLIENTVAR: z.string(),
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
|
||||||
|
* middlewares) or client-side so we need to destruct manually.
|
||||||
|
*/
|
||||||
|
runtimeEnv: {
|
||||||
|
NODE_ENV: process.env.NODE_ENV,
|
||||||
|
// NEXT_PUBLIC_CLIENTVAR: process.env.NEXT_PUBLIC_CLIENTVAR,
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
|
||||||
|
* useful for Docker builds.
|
||||||
|
*/
|
||||||
|
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
|
||||||
|
/**
|
||||||
|
* Makes it so that empty strings are treated as undefined. `SOME_VAR: z.string()` and
|
||||||
|
* `SOME_VAR=''` will throw an error.
|
||||||
|
*/
|
||||||
|
emptyStringAsUndefined: true,
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user