Compare commits

..

1 Commits

Author SHA1 Message Date
c5e912d4ed chore(deps): update dependency react-hook-form to v7.68.0
All checks were successful
Lint / Lint and Typecheck (push) Successful in 45s
Lint / Lint and Typecheck (pull_request) Successful in 40s
2025-12-07 01:46:01 +01:00
13 changed files with 739 additions and 927 deletions

View File

@@ -1,7 +0,0 @@
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git

View File

@@ -1,69 +0,0 @@
# syntax=docker.io/docker/dockerfile:1@sha256:b6afd42430b15f2d2a4c5a02b919e98a525b785b1aaff16747d2f623364e39b6
FROM node:24-alpine@sha256:7e0bd0460b26eb3854ea5b99b887a6a14d665d14cae694b78ae2936d14b2befb AS base
# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED=1
RUN \
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
# Production image, copy all the files and run next
FROM base AS runner
# wget needed for healthcheck
RUN apk add --no-cache wget
WORKDIR /app
ENV NODE_ENV=production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy public files. "[c]" as workaround for conditional matching since the folder might not exist.
COPY --from=builder /app/publi[c] ./public
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

View File

@@ -5,8 +5,6 @@
import './src/env.ts';
/** @type {import("next").NextConfig} */
const config = {
output: 'standalone',
};
const config = {};
export default config;

View File

@@ -33,44 +33,44 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cssnano": "^7.1.2",
"lucide-react": "^0.561.0",
"next": "16.0.10",
"lucide-react": "^0.556.0",
"next": "16.0.7",
"next-plausible": "^3.12.4",
"react": "19.2.3",
"react-dom": "19.2.3",
"react": "19.2.1",
"react-dom": "19.2.1",
"react-hook-form": "^7.56.1",
"recharts": "^2.15.3",
"tailwind-merge": "^3.2.0",
"zod": "^4.0.0"
},
"devDependencies": {
"@playwright/test": "1.57.0",
"@tailwindcss/postcss": "4.1.18",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "6.9.1",
"@testing-library/react": "16.3.0",
"@testing-library/user-event": "14.6.1",
"@types/node": "24.10.3",
"@playwright/test": "^1.57.0",
"@tailwindcss/postcss": "4.1.17",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",
"@types/node": "24.10.1",
"@types/react": "19.2.7",
"@types/react-dom": "19.2.3",
"@vitejs/plugin-react": "5.1.2",
"eslint": "9.39.2",
"eslint-config-next": "16.0.10",
"@vitejs/plugin-react": "^5.1.1",
"eslint": "9.39.1",
"eslint-config-next": "16.0.7",
"eslint-config-prettier": "10.1.8",
"jsdom": "27.3.0",
"jsdom": "^27.2.0",
"postcss": "8.5.6",
"prettier": "3.7.4",
"prettier-plugin-tailwindcss": "0.7.2",
"tailwindcss": "4.1.18",
"tailwindcss": "4.1.17",
"tw-animate-css": "1.4.0",
"typescript": "5.9.3",
"typescript-eslint": "8.49.0",
"vitest": "4.0.15"
"typescript-eslint": "8.48.1",
"vitest": "^4.0.13"
},
"ct3aMetadata": {
"initVersion": "7.39.3"
},
"packageManager": "pnpm@10.25.0",
"packageManager": "pnpm@10.24.0",
"pnpm": {
"overrides": {
"@types/react": "19.2.7",

1417
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,6 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { CoastFireChart } from '@/app/components/charts/CoastFireChart';
import { AuthorBio } from '@/app/components/AuthorBio';
import { FaqSection, type FaqItem } from '@/app/components/FaqSection';
import type { Metadata } from 'next';
const faqs: FaqItem[] = [
{
@@ -40,28 +39,16 @@ const faqs: FaqItem[] = [
},
];
export const metadata: Metadata = {
export const metadata = {
title: `Coast FIRE vs. Lean FIRE: Which Strategy Is Right For You? (${new Date().getFullYear().toString()})`,
description:
'Compare Coast FIRE (front-loading savings) with Lean FIRE (minimalist living). See the math, pros, cons, and find your path to freedom.',
alternates: {
canonical: 'https://investingfire.com/learn/coast-fire-vs-lean-fire',
},
openGraph: {
title: 'Coast FIRE vs. Lean FIRE: The Ultimate Comparison',
description:
"Don't just retire early—retire smarter. We break down the two most popular alternative FIRE strategies.",
type: 'article',
siteName: 'InvestingFIRE',
url: 'https://investingfire.com/learn/coast-fire-vs-lean-fire',
images: [
{
url: 'https://investingfire.com/apple-icon.png',
width: 180,
height: 180,
alt: 'InvestingFIRE Logo',
},
],
},
};

View File

@@ -4,7 +4,6 @@ import { Button } from '@/components/ui/button';
import { Info } from 'lucide-react';
import { AuthorBio } from '@/app/components/AuthorBio';
import { FaqSection, type FaqItem } from '@/app/components/FaqSection';
import type { Metadata } from 'next';
const faqs: FaqItem[] = [
{
@@ -34,27 +33,15 @@ const faqs: FaqItem[] = [
},
];
export const metadata: Metadata = {
export const metadata = {
title: 'Home Bias in Investing: Why It Matters and How to Fix It',
description:
'Home bias concentrates risk in one country. Learn why it happens, how it hurts returns, and simple steps to global diversification.',
alternates: {
canonical: 'https://investingfire.com/learn/home-bias-in-investing',
},
openGraph: {
title: 'Home Bias in Investing: Why It Matters and How to Fix It',
description: 'Reduce country concentration, improve diversification, and stay tax aware.',
type: 'article',
siteName: 'InvestingFIRE',
url: 'https://investingfire.com/learn/home-bias-in-investing',
images: [
{
url: 'https://investingfire.com/apple-icon.png',
width: 180,
height: 180,
alt: 'InvestingFIRE Logo',
},
],
},
};

View File

@@ -2,30 +2,11 @@ import Link from 'next/link';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import BlurThing from '../components/blur-thing';
import { RETIRE_AT_AGE_PRESETS } from '@/lib/retire-at';
import type { Metadata } from 'next';
export const metadata: Metadata = {
export const metadata = {
title: 'Learn FIRE | Financial Independence Guides & Resources',
description:
'Master the art of Financial Independence and Early Retirement. Deep dives into safe withdrawal rates, asset allocation, and FIRE strategies.',
alternates: {
canonical: 'https://investingfire.com/learn',
},
openGraph: {
title: 'Learn FIRE | Financial Independence Guides & Resources',
description:
'Master the art of Financial Independence and Early Retirement. Deep dives into safe withdrawal rates, asset allocation, and FIRE strategies.',
siteName: 'InvestingFIRE',
url: 'https://investingfire.com/learn',
images: [
{
url: 'https://investingfire.com/apple-icon.png',
width: 180,
height: 180,
alt: 'InvestingFIRE Logo',
},
],
},
};
const retireAgeLinks = RETIRE_AT_AGE_PRESETS;

View File

@@ -76,16 +76,7 @@ export const generateMetadata = async ({ params }: RetireAtPageProps): Promise<M
title,
description,
url: canonical,
siteName: 'InvestingFIRE',
type: 'article',
images: [
{
url: 'https://investingfire.com/apple-icon.png',
width: 180,
height: 180,
alt: 'InvestingFIRE Logo',
},
],
},
};
};

View File

@@ -5,7 +5,6 @@ import { Info } from 'lucide-react';
import { FourPercentRuleChart } from '@/app/components/charts/FourPercentRuleChart';
import { AuthorBio } from '@/app/components/AuthorBio';
import { FaqSection, type FaqItem } from '@/app/components/FaqSection';
import type { Metadata } from 'next';
const faqs: FaqItem[] = [
{
@@ -40,26 +39,14 @@ const faqs: FaqItem[] = [
},
];
export const metadata: Metadata = {
export const metadata = {
title: 'Safe Withdrawal Rates & The 4% Rule Explained (2025 Update)',
description: `Is the 4% rule safe in ${new Date().getFullYear().toString()}? We analyze the Trinity Study, sequence of returns risk, and variable withdrawal strategies for a bulletproof retirement.`,
alternates: {
canonical: 'https://investingfire.com/learn/safe-withdrawal-rate-4-percent-rule',
},
openGraph: {
title: 'Safe Withdrawal Rates & The 4% Rule Explained',
description: "Don't run out of money. Understanding the math behind safe retirement withdrawals.",
type: 'article',
siteName: 'InvestingFIRE',
url: 'https://investingfire.com/learn/safe-withdrawal-rate-4-percent-rule',
images: [
{
url: 'https://investingfire.com/apple-icon.png',
width: 180,
height: 180,
alt: 'InvestingFIRE Logo',
},
],
},
};

View File

@@ -3,7 +3,6 @@ import { Button } from '@/components/ui/button';
import { FireFlowchart } from '@/app/components/charts/FireFlowchart';
import { AuthorBio } from '@/app/components/AuthorBio';
import { FaqSection, type FaqItem } from '@/app/components/FaqSection';
import type { Metadata } from 'next';
const faqs: FaqItem[] = [
{
@@ -38,27 +37,15 @@ const faqs: FaqItem[] = [
},
];
export const metadata: Metadata = {
export const metadata = {
title: `What is FIRE? The Ultimate Guide to Financial Independence (${new Date().getFullYear().toString()})`,
description:
'Discover the FIRE movement (Financial Independence, Retire Early). Learn how to calculate your FIRE number, savings rate, and retire decades ahead of schedule.',
alternates: {
canonical: 'https://investingfire.com/learn/what-is-fire',
},
openGraph: {
title: 'What is FIRE? The Ultimate Guide to Financial Independence',
description: 'Stop trading time for money. The comprehensive guide to regaining your freedom.',
type: 'article',
siteName: 'InvestingFIRE',
url: 'https://investingfire.com/learn/what-is-fire',
images: [
{
url: 'https://investingfire.com/apple-icon.png',
width: 180,
height: 180,
alt: 'InvestingFIRE Logo',
},
],
},
};

View File

@@ -5,7 +5,6 @@ import { Button } from '@/components/ui/button';
import { Info } from 'lucide-react';
import { AuthorBio } from '@/app/components/AuthorBio';
import { FaqSection, type FaqItem } from '@/app/components/FaqSection';
import type { Metadata } from 'next';
const faqs: FaqItem[] = [
{
@@ -35,27 +34,15 @@ const faqs: FaqItem[] = [
},
];
export const metadata: Metadata = {
export const metadata = {
title: `Where to Park Your Money for FIRE (${new Date().getFullYear().toString()})`,
description:
'Build a globally diversified, low-cost index portfolio, avoid home bias, and use the right tax wrappers—wherever you live. A practical guide for FIRE investors.',
alternates: {
canonical: 'https://investingfire.com/learn/where-to-park-your-money',
},
openGraph: {
title: 'Where to Park Your Money for FIRE',
description: 'Global index investing playbook: avoid home bias, cut fees, optimize taxes.',
type: 'article',
siteName: 'InvestingFIRE',
url: 'https://investingfire.com/learn/where-to-park-your-money',
images: [
{
url: 'https://investingfire.com/apple-icon.png',
width: 180,
height: 180,
alt: 'InvestingFIRE Logo',
},
],
},
};

View File

@@ -4,7 +4,6 @@ import FireCalculatorForm from './components/FireCalculatorForm';
import BackgroundPattern from './components/BackgroundPattern';
import { FaqSection, type FaqItem } from './components/FaqSection';
import { Testimonials } from './components/Testimonials';
import type { Metadata } from 'next';
const faqs: FaqItem[] = [
{
@@ -39,31 +38,6 @@ const faqs: FaqItem[] = [
},
];
export const metadata: Metadata = {
title: `InvestingFIRE | Finance and Retirement Calculator ${new Date().getFullYear().toString()}`,
description:
'Achieve Financial Independence & Early Retirement! Plan your FIRE journey with the InvestingFIRE calculator and get personal projections in gorgeous graphs..',
alternates: {
canonical: 'https://investingfire.com',
},
openGraph: {
title: `InvestingFIRE | Finance and Retirement Calculator ${new Date().getFullYear().toString()}`,
description:
'Achieve Financial Independence & Early Retirement! Plan your FIRE journey with the InvestingFIRE calculator and get personal projections in gorgeous graphs.',
type: 'website',
url: 'https://investingfire.com',
siteName: 'InvestingFIRE',
images: [
{
url: 'https://investingfire.com/apple-icon.png',
width: 180,
height: 180,
alt: 'InvestingFIRE Logo',
},
],
},
};
export default function HomePage() {
return (
<div className="from-background via-primary/10 to-secondary/10 text-foreground relative flex min-h-screen w-full flex-col items-center overflow-hidden bg-gradient-to-b px-4 pt-6 pb-16">