Over the same time period, more frequent compounding results in more
diff --git a/app/interactives/present-value-calculator-v2/page.tsx b/app/interactives/present-value-calculator-v2/page.tsx
index 26bf490..e25283e 100644
--- a/app/interactives/present-value-calculator-v2/page.tsx
+++ b/app/interactives/present-value-calculator-v2/page.tsx
@@ -14,8 +14,7 @@ import {
SelectValue,
} from "@/app/ui/components/select"
import ThemeToggle from "@/app/lib/theme-toggle"
-import { FaCircleInfo } from "react-icons/fa6"
-
+import InfoPopover from "@/app/ui/components/popover";
type CompoundingFrequency = "annually" | "semi-annually" | "quarterly" | "monthly" | "biweekly" | "weekly" | "daily"
@@ -665,21 +664,10 @@ export default function PresentValueCalculator() {
Final amount (optional)
-
-
+
A lump sum received or paid at the end of the payment
series (also called final value or future value).
-
+
From 2aa567631123be4b3038e332f0c1f14b079b834b Mon Sep 17 00:00:00 2001
From: Jen Breese-Kauth
Date: Wed, 17 Jun 2026 17:17:24 -0700
Subject: [PATCH 2/2] fixups
---
.../present-value-calculator-v2/page.tsx | 64 ++++++++++---------
1 file changed, 35 insertions(+), 29 deletions(-)
diff --git a/app/interactives/present-value-calculator-v2/page.tsx b/app/interactives/present-value-calculator-v2/page.tsx
index e25283e..4093960 100644
--- a/app/interactives/present-value-calculator-v2/page.tsx
+++ b/app/interactives/present-value-calculator-v2/page.tsx
@@ -88,7 +88,8 @@ export default function PresentValueCalculator() {
// Warning states (amber — calc still runs)
const [interestRateWarning, setInterestRateWarning] = useState("")
const [paymentInterestRateWarning, setPaymentInterestRateWarning] = useState("")
- const [futureValueWarning, setFutureValueWarning] = useState("")
+ const [timePeriodWarning, setTimePeriodWarning] = useState("")
+ const [numberOfPaymentsWarning, setNumberOfPaymentsWarning] = useState("")
// Derived max periods for each tab
const singleMaxPeriods = frequencyMap[compoundingFrequency].periods * 100
@@ -134,10 +135,10 @@ export default function PresentValueCalculator() {
setTimePeriod("")
setCompoundingFrequency("annually")
setFutureValueError("")
- setFutureValueWarning("")
setInterestRateError("")
setTimePeriodError("")
setInterestRateWarning("")
+ setTimePeriodWarning("")
}
const resetSeries = () => {
@@ -151,6 +152,7 @@ export default function PresentValueCalculator() {
setNumberOfPaymentsError("")
setFinalAmountError("")
setPaymentInterestRateWarning("")
+ setNumberOfPaymentsWarning("")
}
const singleCalculations = useMemo(() => {
@@ -253,7 +255,6 @@ export default function PresentValueCalculator() {
const raw = e.target.value;
if (raw === "") {
setFutureValueError("");
- setFutureValueWarning("");
setFutureValue("");
return;
}
@@ -262,16 +263,10 @@ export default function PresentValueCalculator() {
setFutureValueError(
"Enter an amount between 0 and 1,000,000,000.",
);
- setFutureValueWarning("");
setFutureValue(raw);
return;
}
setFutureValueError("");
- setFutureValueWarning(
- val === 0
- ? "A future value of $0 has no present value to calculate."
- : "",
- );
setFutureValue(raw);
}}
onBlur={(e) => {
@@ -279,7 +274,6 @@ export default function PresentValueCalculator() {
const val = parseFloat(raw);
if (raw === "" || isNaN(val)) {
setFutureValue("");
- setFutureValueWarning("");
setTimeout(
() =>
setFutureValueError(
@@ -291,15 +285,10 @@ export default function PresentValueCalculator() {
setFutureValue(String(val));
} else {
setFutureValueError("");
- setFutureValueWarning(
- val === 0
- ? "A future value of $0 has no present value to calculate."
- : "",
- );
setFutureValue(String(val));
}
}}
- className={`border-1 w-full rounded-md shadow-sm py-2 px-3 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none ${parseFloat(futureValue) > 0 ? "pl-7" : "pl-8"} ${futureValueError ? "border-[var(--color-inline-error)] border-2" : futureValueWarning ? "border-amber-500 border-2" : ""}`}
+ className={`border-1 w-full rounded-md shadow-sm py-2 px-3 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none ${parseFloat(futureValue) > 0 ? "pl-7" : "pl-8"} ${futureValueError ? "border-[var(--color-inline-error)] border-2" : ""}`}
min={0}
max={1000000000}
/>
@@ -312,11 +301,6 @@ export default function PresentValueCalculator() {
{futureValueError}
)}
- {futureValueWarning && (
-
- {futureValueWarning}
-
- )}
{/* Interest Rate */}
@@ -430,21 +414,27 @@ export default function PresentValueCalculator() {
if (raw === "") {
setTimePeriod("");
setTimePeriodError("");
+ setTimePeriodWarning("");
return;
}
const val = Number(raw);
+ setTimePeriod(raw);
if (val < 0 || val > singleMaxPeriods) {
- setTimePeriod("");
setTimePeriodError(
buildPeriodsRangeError(
compoundingFrequency,
singleMaxPeriods,
),
);
- return;
+ setTimePeriodWarning("");
+ } else {
+ setTimePeriodError("");
+ setTimePeriodWarning(
+ val === 0
+ ? "0 periods = today. No periodic payments occur. Only a final amount today affects the present value."
+ : "",
+ );
}
- setTimePeriodError("");
- setTimePeriod(raw);
}}
onBlur={(e) => {
const raw = e.target.value;
@@ -476,6 +466,11 @@ export default function PresentValueCalculator() {
{timePeriodError}