import { useState, useCallback } from 'react'; import { Route } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import type { VesselData, TripEstimate, CurrencyCode } from '../types'; import { calculateTripCarbon, calculateCarbonFromFuel } from '../utils/carbonCalculator'; import { currencies, formatCurrency } from '../utils/currencies'; import { CurrencySelect } from './CurrencySelect'; interface Props { vesselData: VesselData; onOffsetClick?: (tons: number, monetaryAmount?: number) => void; } export function TripCalculator({ vesselData, onOffsetClick }: Props) { const [calculationType, setCalculationType] = useState<'fuel' | 'distance' | 'custom'>('fuel'); const [distance, setDistance] = useState(''); const [speed, setSpeed] = useState('12'); const [fuelRate, setFuelRate] = useState('100'); const [fuelAmount, setFuelAmount] = useState(''); const [fuelUnit, setFuelUnit] = useState<'liters' | 'gallons'>('liters'); const [tripEstimate, setTripEstimate] = useState(null); const [currency, setCurrency] = useState('USD'); const [offsetPercentage, setOffsetPercentage] = useState(100); const [customPercentage, setCustomPercentage] = useState(''); const [customAmount, setCustomAmount] = useState(''); const handleCalculate = useCallback((e: React.FormEvent) => { e.preventDefault(); if (calculationType === 'distance') { const estimate = calculateTripCarbon( vesselData, Number(distance), Number(speed), Number(fuelRate) ); setTripEstimate(estimate); } else if (calculationType === 'fuel') { const co2Emissions = calculateCarbonFromFuel(Number(fuelAmount), fuelUnit === 'gallons'); setTripEstimate({ distance: 0, duration: 0, fuelConsumption: Number(fuelAmount), co2Emissions }); } }, [calculationType, distance, speed, fuelRate, fuelAmount, fuelUnit, vesselData]); const handleCustomPercentageChange = useCallback((e: React.ChangeEvent) => { const value = e.target.value; if (value === '' || (Number(value) >= 0 && Number(value) <= 100)) { setCustomPercentage(value); if (value !== '') { setOffsetPercentage(Number(value)); } } }, []); const handlePresetPercentage = useCallback((percentage: number) => { setOffsetPercentage(percentage); setCustomPercentage(''); }, []); const calculateOffsetAmount = useCallback((emissions: number, percentage: number) => { return (emissions * percentage) / 100; }, []); const handleCustomAmountChange = useCallback((e: React.ChangeEvent) => { const value = e.target.value; if (value === '' || Number(value) >= 0) { setCustomAmount(value); } }, []); // Animation variants const fadeIn = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { duration: 0.5 } } }; const slideIn = { hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0, transition: { duration: 0.5, ease: [0.25, 0.1, 0.25, 1.0] } } }; return (

Carbon Offset Calculator

setCalculationType('fuel')} className={`px-4 py-2 rounded-lg transition-colors ${ calculationType === 'fuel' ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200' }`} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} transition={{ type: "spring", stiffness: 400, damping: 17 }} > Fuel Based setCalculationType('distance')} className={`px-4 py-2 rounded-lg transition-colors ${ calculationType === 'distance' ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200' }`} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} transition={{ type: "spring", stiffness: 400, damping: 17 }} > Distance Based setCalculationType('custom')} className={`px-4 py-2 rounded-lg transition-colors ${ calculationType === 'custom' ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200' }`} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} transition={{ type: "spring", stiffness: 400, damping: 17 }} > Custom Amount
{calculationType === 'custom' ? (
{currencies[currency].symbol}
{currency}
{customAmount && Number(customAmount) > 0 && ( onOffsetClick?.(0, Number(customAmount))} className="w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 transition-colors mt-6" whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.97 }} > Offset Your Impact )}
) : ( {calculationType === 'fuel' && (
setFuelAmount(e.target.value)} placeholder="Enter amount" className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-200" required />
)} {calculationType === 'distance' && ( <> setDistance(e.target.value)} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-200" required /> setSpeed(e.target.value)} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-200" required /> setFuelRate(e.target.value)} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-200" required />

Typical range: 50 - 500 liters per hour for most yachts

)}
Calculate Impact
)}
{tripEstimate && calculationType !== 'custom' && ( {calculationType === 'distance' && (

Trip Duration

{tripEstimate.duration.toFixed(1)} hours

)}

Fuel Consumption

{tripEstimate.fuelConsumption.toLocaleString()} {fuelUnit}

{[100, 75, 50, 25].map((percent, index) => ( handlePresetPercentage(percent)} className={`px-4 py-2 rounded-lg transition-colors ${ offsetPercentage === percent && customPercentage === '' ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200' }`} whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3, delay: 0.6 + (index * 0.1), type: "spring", stiffness: 400, damping: 17 }} > {percent}% ))} %

Selected CO₂ Offset

{calculateOffsetAmount(tripEstimate.co2Emissions, offsetPercentage).toFixed(2)} tons

{offsetPercentage}% of {tripEstimate.co2Emissions.toFixed(2)} tons

onOffsetClick?.(calculateOffsetAmount(tripEstimate.co2Emissions, offsetPercentage))} className="w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 transition-colors" whileHover={{ scale: 1.03 }} whileTap={{ scale: 0.97 }} initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, delay: 1.2, type: "spring", stiffness: 400, damping: 17 }} > Offset Your Impact
)}
); }