From e21756d7f0258b6b64f52a0a608672e6954cee1a Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 30 Oct 2025 15:40:49 +0100 Subject: [PATCH] Fix custom amount tons calculation and payment link failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root Cause: When users entered a custom monetary amount, the tons calculation was broken: - actualOffsetTons was calculated as (tons * offsetPercentage) / 100 - When monetaryAmount was provided, tons was 0, so actualOffsetTons = 0 - This caused tons display to show 0 and payment link to fail (0 tons invalid) Fix Applied: 1. Moved roundedPricePerTon calculation earlier in component lifecycle 2. Calculate baseTons from monetaryAmount when provided: baseTons = monetaryAmount / roundedPricePerTon 3. Then apply offset percentage: actualOffsetTons = (baseTons * offsetPercentage) / 100 Example: - User enters $1,000 custom amount - Portfolio price = $238/ton (rounded up) - baseTons = 1000 / 238 = 4.20 tons - With 100% offset: actualOffsetTons = 4.20 tons - Payment link now passes 4.20 tons to Stripe ✓ Files Modified: - src/components/OffsetOrder.tsx - src/components/MobileOffsetOrder.tsx 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/components/MobileOffsetOrder.tsx | 8 ++++++-- src/components/OffsetOrder.tsx | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/components/MobileOffsetOrder.tsx b/src/components/MobileOffsetOrder.tsx index 22bc21e..03de30b 100644 --- a/src/components/MobileOffsetOrder.tsx +++ b/src/components/MobileOffsetOrder.tsx @@ -73,8 +73,13 @@ export function MobileOffsetOrder({ tons, monetaryAmount, onBack }: Props) { savedState?.offsetPercentage ?? 100 // Default to 100% or use saved value ); + // Calculate price per ton (rounded up) + const roundedPricePerTon = portfolio ? Math.ceil(portfolio.pricePerTon || 18) : 18; + // Calculate the actual tons to offset based on percentage - const actualOffsetTons = (tons * offsetPercentage) / 100; + // If monetaryAmount is provided (custom amount), calculate tons from the monetary amount + const baseTons = monetaryAmount ? (monetaryAmount / roundedPricePerTon) : tons; + const actualOffsetTons = (baseTons * offsetPercentage) / 100; // Format tons for display const formatTons = (tons: number): string => { @@ -214,7 +219,6 @@ export function MobileOffsetOrder({ tons, monetaryAmount, onBack }: Props) { }; // Calculate offset cost using the portfolio price (rounded UP to match display) - const roundedPricePerTon = portfolio ? Math.ceil(portfolio.pricePerTon || 18) : 18; const offsetCost = monetaryAmount || (portfolio ? actualOffsetTons * roundedPricePerTon : 0); const handleInputChange = (field: keyof typeof formData, value: string) => { diff --git a/src/components/OffsetOrder.tsx b/src/components/OffsetOrder.tsx index 6368e38..8032af6 100644 --- a/src/components/OffsetOrder.tsx +++ b/src/components/OffsetOrder.tsx @@ -77,8 +77,13 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr savedState?.offsetPercentage ?? 100 // Default to 100% or use saved value ); + // Calculate price per ton (rounded up) + const roundedPricePerTon = portfolio ? Math.ceil(portfolio.pricePerTon || 18) : 18; + // Calculate the actual tons to offset based on percentage - const actualOffsetTons = (tons * offsetPercentage) / 100; + // If monetaryAmount is provided (custom amount), calculate tons from the monetary amount + const baseTons = monetaryAmount ? (monetaryAmount / roundedPricePerTon) : tons; + const actualOffsetTons = (baseTons * offsetPercentage) / 100; // Format tons for display const formatTons = (tons: number): string => { @@ -193,7 +198,6 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr }; // Calculate offset cost using the portfolio price (rounded UP to match display) - const roundedPricePerTon = portfolio ? Math.ceil(portfolio.pricePerTon || 18) : 18; const offsetCost = monetaryAmount || (portfolio ? actualOffsetTons * roundedPricePerTon : 0); return (