diff --git a/puffin-calculator-integrated.php b/puffin-calculator-integrated.php
new file mode 100644
index 0000000..7024fcf
--- /dev/null
+++ b/puffin-calculator-integrated.php
@@ -0,0 +1,996 @@
+ '100%',
+ 'height' => 'auto',
+ 'theme' => 'light',
+ ), $atts);
+
+ // Generate unique ID for this instance
+ $calculator_id = 'puffin-calculator-' . uniqid();
+
+ // Start output buffer
+ ob_start();
+ ?>
+
+
+
+ get_calculator_styles());
+
+ // Register and enqueue the calculator script
+ wp_register_script('puffin-calculator', '', array('react', 'react-dom'), '1.0.0', true);
+ wp_enqueue_script('puffin-calculator');
+
+ // Add the calculator script as inline JS
+ wp_add_inline_script('puffin-calculator', $this->get_calculator_script());
+ }
+
+ /**
+ * Get the inline calculator styles
+ */
+ private function get_calculator_styles() {
+ return "
+ .puffin-calculator-wrapper {
+ margin: 20px 0;
+ width: 100%;
+ max-width: 100%;
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ }
+
+ .puffin-calculator {
+ border: none;
+ width: 100%;
+ min-height: 600px;
+ background-color: #f9fafb;
+ }
+
+ @media (max-width: 768px) {
+ .puffin-calculator-wrapper {
+ margin: 15px 0;
+ }
+
+ .puffin-calculator {
+ min-height: 800px;
+ }
+ }
+ ";
+ }
+
+ /**
+ * Get the inline calculator script
+ */
+ private function get_calculator_script() {
+ return "
+ // Initialize the Puffin Calculator
+ function initPuffinCalculator(element) {
+ 'use strict';
+
+ // React and ReactDOM are loaded from CDN
+ const React = window.React;
+ const ReactDOM = window.ReactDOM;
+ const { useState, useEffect, useCallback } = React;
+
+ // ==================== TYPE DEFINITIONS ====================
+
+ // VesselData interface
+ // imo: string;
+ // vesselName: string;
+ // type: string;
+ // length: number;
+ // width: number;
+ // estimatedEnginePower: number;
+
+ // TripEstimate interface
+ // distance: number; // nautical miles
+ // duration: number; // hours
+ // fuelConsumption: number; // liters
+ // co2Emissions: number; // tons
+
+ // Currency interface
+ // code: string;
+ // symbol: string;
+ // rate: number; // Exchange rate relative to USD
+
+ // ==================== UTILITIES ====================
+
+ // Mock vessel data
+ const sampleVessel = {
+ imo: '1234567',
+ vesselName: 'Sample Yacht',
+ type: 'Yacht',
+ length: 50,
+ width: 9,
+ estimatedEnginePower: 2250
+ };
+
+ // Constants for carbon calculations
+ const EMISSION_FACTOR = 3.206; // tons of CO₂ per ton of fuel
+ const FUEL_DENSITY = 0.85; // tons per m³ (or metric tons per kiloliter)
+ const GALLONS_TO_LITERS = 3.78541; // 1 US gallon = 3.78541 liters
+ const LITERS_TO_CUBIC_METERS = 0.001; // 1 liter = 0.001 m³
+
+ // Available currencies
+ const currencies = {
+ USD: { code: 'USD', symbol: '$', rate: 1 },
+ EUR: { code: 'EUR', symbol: '€', rate: 0.92 },
+ GBP: { code: 'GBP', symbol: '£', rate: 0.79 },
+ CHF: { code: 'CHF', symbol: 'CHF', rate: 0.88 },
+ };
+
+ // Format currency
+ function formatCurrency(amountUSD, currency) {
+ if (!currency) {
+ currency = currencies.USD;
+ }
+
+ // Convert USD amount to target currency
+ const convertedAmount = amountUSD * currency.rate;
+
+ return `${currency.symbol}${convertedAmount.toLocaleString(undefined, {
+ minimumFractionDigits: 0,
+ maximumFractionDigits: 0,
+ })}`;
+ }
+
+ // Calculate trip carbon
+ function calculateTripCarbon(vesselData, distance, speed, fuelRateLitersPerHour) {
+ const tripHours = distance / speed;
+
+ // Calculate total fuel consumption in liters
+ const fuelConsumptionLiters = fuelRateLitersPerHour * tripHours;
+
+ // Convert liters to tons for CO₂ calculation
+ const fuelConsumptionTons = (fuelConsumptionLiters * LITERS_TO_CUBIC_METERS) * FUEL_DENSITY;
+
+ // Calculate CO₂ emissions
+ const fuelRateTonsPerHour = (fuelRateLitersPerHour * LITERS_TO_CUBIC_METERS) * FUEL_DENSITY;
+ const emissionsPerNM = (fuelRateTonsPerHour * EMISSION_FACTOR) / speed;
+ const totalEmissions = emissionsPerNM * distance;
+
+ return {
+ distance,
+ duration: tripHours,
+ fuelConsumption: Math.round(fuelConsumptionLiters),
+ co2Emissions: Number(totalEmissions.toFixed(2))
+ };
+ }
+
+ // Calculate carbon from fuel
+ function calculateCarbonFromFuel(fuelAmount, isGallons = false) {
+ // Convert to liters if input is in gallons
+ const liters = isGallons ? fuelAmount * GALLONS_TO_LITERS : fuelAmount;
+
+ // Convert liters to cubic meters (m³)
+ const cubicMeters = liters * LITERS_TO_CUBIC_METERS;
+
+ // Convert volume to mass (tons)
+ const fuelTons = cubicMeters * FUEL_DENSITY;
+
+ // Calculate CO₂ emissions
+ const co2Emissions = fuelTons * EMISSION_FACTOR;
+
+ return Number(co2Emissions.toFixed(2));
+ }
+
+ // Analytics object (simplified)
+ const analytics = {
+ pageView: (path) => {
+ // Simplified analytics - would integrate with WordPress analytics in a real implementation
+ console.log(`Page view: ${path}`);
+ },
+ event: (category, action, label) => {
+ console.log(`Event: ${category} - ${action} - ${label}`);
+ }
+ };
+
+ // ==================== COMPONENTS ====================
+
+ // CurrencySelect Component
+ function CurrencySelect({ value, onChange }) {
+ return React.createElement('select', {
+ value: value,
+ onChange: (e) => onChange(e.target.value),
+ className: 'block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring focus:ring-blue-200 focus:ring-opacity-50 p-2'
+ },
+ Object.entries(currencies).map(([code, currency]) => (
+ React.createElement('option', {
+ key: code,
+ value: code
+ }, `${currency.symbol} ${code}`)
+ )));
+ }
+
+ // TripCalculator Component
+ function TripCalculator({ vesselData, onOffsetClick }) {
+ const [calculationType, setCalculationType] = useState('fuel');
+ const [distance, setDistance] = useState('');
+ const [speed, setSpeed] = useState('12');
+ const [fuelRate, setFuelRate] = useState('100');
+ const [fuelAmount, setFuelAmount] = useState('');
+ const [fuelUnit, setFuelUnit] = useState('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) => {
+ 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) => {
+ const value = e.target.value;
+ if (value === '' || (Number(value) >= 0 && Number(value) <= 100)) {
+ setCustomPercentage(value);
+ if (value !== '') {
+ setOffsetPercentage(Number(value));
+ }
+ }
+ }, []);
+
+ const handlePresetPercentage = useCallback((percentage) => {
+ setOffsetPercentage(percentage);
+ setCustomPercentage('');
+ }, []);
+
+ const calculateOffsetAmount = useCallback((emissions, percentage) => {
+ return (emissions * percentage) / 100;
+ }, []);
+
+ const handleCustomAmountChange = useCallback((e) => {
+ const value = e.target.value;
+ if (value === '' || Number(value) >= 0) {
+ setCustomAmount(value);
+ }
+ }, []);
+
+ return React.createElement('div', {
+ className: 'bg-white rounded-lg shadow-xl p-6 max-w-2xl w-full mt-8'
+ }, [
+ // Header
+ React.createElement('div', {
+ key: 'header',
+ className: 'flex items-center justify-between mb-6'
+ }, [
+ React.createElement('h2', {
+ key: 'title',
+ className: 'text-2xl font-bold text-gray-800'
+ }, 'Carbon Offset Calculator'),
+ // Route icon would be here
+ ]),
+
+ // Calculation Method
+ React.createElement('div', {
+ key: 'calc-method',
+ className: 'mb-6'
+ }, [
+ React.createElement('label', {
+ key: 'method-label',
+ className: 'block text-sm font-medium text-gray-700 mb-2'
+ }, 'Calculation Method'),
+ React.createElement('div', {
+ key: 'method-buttons',
+ className: 'flex flex-wrap gap-3'
+ }, [
+ React.createElement('button', {
+ key: 'fuel-btn',
+ type: 'button',
+ onClick: () => 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'
+ }`
+ }, 'Fuel Based'),
+ React.createElement('button', {
+ key: 'distance-btn',
+ type: 'button',
+ onClick: () => 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'
+ }`
+ }, 'Distance Based'),
+ React.createElement('button', {
+ key: 'custom-btn',
+ type: 'button',
+ onClick: () => 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'
+ }`
+ }, 'Custom Amount')
+ ])
+ ]),
+
+ // Custom Amount Form
+ calculationType === 'custom' ? React.createElement('div', {
+ key: 'custom-form',
+ className: 'space-y-4'
+ }, [
+ // Currency Select
+ React.createElement('div', {
+ key: 'currency-select',
+ }, [
+ React.createElement('label', {
+ className: 'block text-sm font-medium text-gray-700 mb-2'
+ }, 'Select Currency'),
+ React.createElement('div', {
+ className: 'max-w-xs'
+ }, [
+ React.createElement(CurrencySelect, {
+ value: currency,
+ onChange: setCurrency
+ })
+ ])
+ ]),
+
+ // Amount Input
+ React.createElement('div', {
+ key: 'amount-input',
+ }, [
+ React.createElement('label', {
+ className: 'block text-sm font-medium text-gray-700 mb-2'
+ }, 'Enter Amount to Offset'),
+ React.createElement('div', {
+ className: 'relative rounded-md shadow-sm'
+ }, [
+ React.createElement('div', {
+ className: 'pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3'
+ }, [
+ React.createElement('span', {
+ className: 'text-gray-500 sm:text-sm'
+ }, currencies[currency].symbol)
+ ]),
+ React.createElement('input', {
+ type: 'number',
+ value: customAmount,
+ onChange: handleCustomAmountChange,
+ placeholder: 'Enter amount',
+ min: '0',
+ className: 'mt-1 block w-full rounded-md border-gray-300 pl-7 pr-12 focus:border-blue-500 focus:ring-blue-500 sm:text-sm p-2',
+ required: true
+ }),
+ React.createElement('div', {
+ className: 'pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3'
+ }, [
+ React.createElement('span', {
+ className: 'text-gray-500 sm:text-sm'
+ }, currency)
+ ])
+ ])
+ ]),
+
+ // Offset Button
+ customAmount && Number(customAmount) > 0 ? React.createElement('button', {
+ key: 'offset-btn',
+ onClick: () => 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'
+ }, 'Offset Your Impact') : null
+ ]) :
+ // Trip Calculator Form
+ React.createElement('form', {
+ key: 'trip-form',
+ onSubmit: handleCalculate,
+ className: 'space-y-4'
+ }, [
+ // Fuel Based Form
+ calculationType === 'fuel' ? React.createElement('div', {
+ key: 'fuel-form'
+ }, [
+ React.createElement('label', {
+ className: 'block text-sm font-medium text-gray-700'
+ }, 'Fuel Consumption'),
+ React.createElement('div', {
+ className: 'flex space-x-4'
+ }, [
+ React.createElement('div', {
+ className: 'flex-1'
+ }, [
+ React.createElement('input', {
+ type: 'number',
+ min: '1',
+ value: fuelAmount,
+ onChange: (e) => 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 p-2',
+ required: true
+ })
+ ]),
+ React.createElement('div', {}, [
+ React.createElement('select', {
+ value: fuelUnit,
+ onChange: (e) => setFuelUnit(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 p-2'
+ }, [
+ React.createElement('option', {
+ key: 'liters',
+ value: 'liters'
+ }, 'Liters'),
+ React.createElement('option', {
+ key: 'gallons',
+ value: 'gallons'
+ }, 'Gallons')
+ ])
+ ])
+ ])
+ ]) : null,
+
+ // Distance Based Form
+ calculationType === 'distance' ? React.createElement(React.Fragment, {
+ key: 'distance-form'
+ }, [
+ React.createElement('div', {
+ key: 'distance-input'
+ }, [
+ React.createElement('label', {
+ className: 'block text-sm font-medium text-gray-700'
+ }, 'Distance (nautical miles)'),
+ React.createElement('input', {
+ type: 'number',
+ min: '1',
+ value: distance,
+ onChange: (e) => 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 p-2',
+ required: true
+ })
+ ]),
+
+ React.createElement('div', {
+ key: 'speed-input'
+ }, [
+ React.createElement('label', {
+ className: 'block text-sm font-medium text-gray-700'
+ }, 'Average Speed (knots)'),
+ React.createElement('input', {
+ type: 'number',
+ min: '1',
+ max: '50',
+ value: speed,
+ onChange: (e) => 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 p-2',
+ required: true
+ })
+ ]),
+
+ React.createElement('div', {
+ key: 'fuel-rate-input'
+ }, [
+ React.createElement('label', {
+ className: 'block text-sm font-medium text-gray-700'
+ }, 'Fuel Consumption Rate (liters per hour)'),
+ React.createElement('input', {
+ type: 'number',
+ min: '1',
+ step: '1',
+ value: fuelRate,
+ onChange: (e) => 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 p-2',
+ required: true
+ }),
+ React.createElement('p', {
+ className: 'mt-1 text-sm text-gray-500'
+ }, 'Typical range: 50 - 500 liters per hour for most yachts')
+ ])
+ ]) : null,
+
+ // Common Form Elements
+ React.createElement('div', {
+ key: 'currency-select'
+ }, [
+ React.createElement('label', {
+ className: 'block text-sm font-medium text-gray-700'
+ }, 'Select Currency'),
+ React.createElement('div', {
+ className: 'max-w-xs'
+ }, [
+ React.createElement(CurrencySelect, {
+ value: currency,
+ onChange: setCurrency
+ })
+ ])
+ ]),
+
+ React.createElement('button', {
+ key: 'calculate-btn',
+ type: 'submit',
+ className: 'w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 transition-colors'
+ }, 'Calculate Impact')
+ ]),
+
+ // Results Section
+ tripEstimate && calculationType !== 'custom' ? React.createElement('div', {
+ key: 'results',
+ className: 'mt-6 space-y-6'
+ }, [
+ // Trip Details
+ React.createElement('div', {
+ key: 'trip-details',
+ className: 'grid grid-cols-2 gap-4'
+ }, [
+ // Trip Duration (only for distance calculation)
+ calculationType === 'distance' ? React.createElement('div', {
+ key: 'duration',
+ className: 'bg-gray-50 p-4 rounded-lg'
+ }, [
+ React.createElement('p', {
+ className: 'text-sm text-gray-600'
+ }, 'Trip Duration'),
+ React.createElement('p', {
+ className: 'text-xl font-bold text-gray-900'
+ }, `${tripEstimate.duration.toFixed(1)} hours`)
+ ]) : null,
+
+ // Fuel Consumption
+ React.createElement('div', {
+ key: 'fuel',
+ className: 'bg-gray-50 p-4 rounded-lg'
+ }, [
+ React.createElement('p', {
+ className: 'text-sm text-gray-600'
+ }, 'Fuel Consumption'),
+ React.createElement('p', {
+ className: 'text-xl font-bold text-gray-900'
+ }, `${tripEstimate.fuelConsumption.toLocaleString()} ${fuelUnit}`)
+ ])
+ ]),
+
+ // Offset Percentage Selection
+ React.createElement('div', {
+ key: 'offset-percent',
+ }, [
+ React.createElement('label', {
+ className: 'block text-sm font-medium text-gray-700 mb-2'
+ }, 'Offset Percentage'),
+ React.createElement('div', {
+ className: 'flex flex-wrap gap-3 mb-3'
+ }, [
+ // Preset percentage buttons
+ [100, 75, 50, 25].map((percent) => (
+ React.createElement('button', {
+ key: `percent-${percent}`,
+ type: 'button',
+ onClick: () => 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'
+ }`
+ }, `${percent}%`)
+ )),
+
+ // Custom percentage input
+ React.createElement('div', {
+ className: 'flex items-center space-x-2'
+ }, [
+ React.createElement('input', {
+ type: 'number',
+ value: customPercentage,
+ onChange: handleCustomPercentageChange,
+ placeholder: 'Custom %',
+ min: '0',
+ max: '100',
+ className: 'w-24 px-3 py-2 border rounded-lg focus:ring-blue-500 focus:border-blue-500'
+ }),
+ React.createElement('span', {
+ className: 'text-gray-600'
+ }, '%')
+ ])
+ ])
+ ]),
+
+ // Selected CO₂ Offset
+ React.createElement('div', {
+ key: 'co2-offset',
+ className: 'bg-blue-50 p-4 rounded-lg'
+ }, [
+ React.createElement('p', {
+ className: 'text-sm text-gray-600'
+ }, 'Selected CO₂ Offset'),
+ React.createElement('p', {
+ className: 'text-2xl font-bold text-blue-900'
+ }, `${calculateOffsetAmount(tripEstimate.co2Emissions, offsetPercentage).toFixed(2)} tons`),
+ React.createElement('p', {
+ className: 'text-sm text-blue-600 mt-1'
+ }, `${offsetPercentage}% of ${tripEstimate.co2Emissions.toFixed(2)} tons`)
+ ]),
+
+ // Offset Button
+ React.createElement('button', {
+ key: 'offset-btn',
+ onClick: () => 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'
+ }, 'Offset Your Impact')
+ ]) : null
+ ]);
+ }
+
+ // OffsetOrder Component
+ function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }) {
+ const [name, setName] = useState('');
+ const [email, setEmail] = useState('');
+ const [currency, setCurrency] = useState('USD');
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [isSuccess, setIsSuccess] = useState(false);
+ const [error, setError] = useState('');
+
+ const handleSubmit = (e) => {
+ e.preventDefault();
+ setIsSubmitting(true);
+ setError('');
+
+ // Simulate API call
+ setTimeout(() => {
+ // Send analytics event
+ analytics.event('offset', 'purchase', `${tons} tons`);
+
+ setIsSubmitting(false);
+ setIsSuccess(true);
+ }, 1500);
+ };
+
+ if (isSuccess) {
+ return React.createElement('div', {
+ className: 'bg-white rounded-lg shadow-xl p-6 max-w-2xl w-full'
+ }, [
+ React.createElement('div', {
+ key: 'success-icon',
+ className: 'flex justify-center mb-6'
+ }, [
+ // Success checkmark icon (simplified)
+ React.createElement('div', {
+ className: 'w-16 h-16 bg-green-100 rounded-full flex items-center justify-center'
+ }, [
+ React.createElement('span', {
+ className: 'text-green-500 text-2xl'
+ }, '✓')
+ ])
+ ]),
+ React.createElement('h2', {
+ key: 'success-title',
+ className: 'text-2xl font-bold text-gray-800 text-center mb-4'
+ }, 'Thank You for Your Contribution!'),
+ React.createElement('p', {
+ key: 'success-message',
+ className: 'text-gray-600 text-center mb-6'
+ }, monetaryAmount
+ ? `Your contribution of ${formatCurrency(monetaryAmount, currencies[currency])} has been received.`
+ : `Your offset of ${tons.toFixed(2)} tons of CO₂ has been successfully processed.`),
+ React.createElement('p', {
+ key: 'success-email',
+ className: 'text-gray-600 text-center mb-8'
+ }, `A confirmation email has been sent to ${email}.`),
+ React.createElement('button', {
+ key: 'back-btn',
+ onClick: onBack,
+ className: 'block w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 transition-colors'
+ }, 'Return to Calculator')
+ ]);
+ }
+
+ return React.createElement('div', {
+ className: 'bg-white rounded-lg shadow-xl p-6 max-w-2xl w-full'
+ }, [
+ // Back button
+ React.createElement('button', {
+ key: 'back-button',
+ onClick: onBack,
+ className: 'text-sm text-blue-500 mb-6 flex items-center'
+ }, '← Back to Calculator'),
+
+ React.createElement('h2', {
+ key: 'title',
+ className: 'text-2xl font-bold text-gray-800 mb-6'
+ }, 'Complete Your Carbon Offset'),
+
+ // Description
+ React.createElement('div', {
+ key: 'description',
+ className: 'mb-6'
+ }, [
+ React.createElement('div', {
+ className: 'p-4 bg-blue-50 rounded-lg mb-4'
+ }, [
+ React.createElement('p', {
+ className: 'font-semibold text-blue-800'
+ }, monetaryAmount
+ ? `You're contributing: ${formatCurrency(monetaryAmount, currencies[currency])}`
+ : `You're offsetting: ${tons.toFixed(2)} tons of CO₂`)
+ ]),
+ React.createElement('p', {
+ className: 'text-gray-600'
+ }, 'Your offset will be invested in certified projects that reduce greenhouse gas emissions and support sustainable development.')
+ ]),
+
+ // Form
+ React.createElement('form', {
+ key: 'form',
+ onSubmit: handleSubmit,
+ className: 'space-y-4'
+ }, [
+ // Name field
+ React.createElement('div', {}, [
+ React.createElement('label', {
+ htmlFor: 'name',
+ className: 'block text-sm font-medium text-gray-700 mb-1'
+ }, 'Full Name'),
+ React.createElement('input', {
+ id: 'name',
+ type: 'text',
+ value: name,
+ onChange: (e) => setName(e.target.value),
+ className: 'w-full p-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500',
+ required: true
+ })
+ ]),
+
+ // Email field
+ React.createElement('div', {}, [
+ React.createElement('label', {
+ htmlFor: 'email',
+ className: 'block text-sm font-medium text-gray-700 mb-1'
+ }, 'Email Address'),
+ React.createElement('input', {
+ id: 'email',
+ type: 'email',
+ value: email,
+ onChange: (e) => setEmail(e.target.value),
+ className: 'w-full p-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500',
+ required: true
+ })
+ ]),
+
+ // Currency field
+ React.createElement('div', {}, [
+ React.createElement('label', {
+ htmlFor: 'currency',
+ className: 'block text-sm font-medium text-gray-700 mb-1'
+ }, 'Currency'),
+ React.createElement('div', {
+ className: 'max-w-xs'
+ }, [
+ React.createElement(CurrencySelect, {
+ value: currency,
+ onChange: setCurrency
+ })
+ ])
+ ]),
+
+ // Error message
+ error ? React.createElement('div', {
+ className: 'p-3 bg-red-50 text-red-700 rounded-md'
+ }, error) : null,
+
+ // Submit button
+ React.createElement('button', {
+ type: 'submit',
+ disabled: isSubmitting,
+ className: `w-full bg-blue-500 text-white py-2 px-4 rounded-lg hover:bg-blue-600 transition-colors ${
+ isSubmitting ? 'opacity-70 cursor-not-allowed' : ''
+ }`
+ }, isSubmitting ? 'Processing...' : 'Complete Offset')
+ ])
+ ]);
+ }
+
+ // Main App Component
+ function App() {
+ const [currentPage, setCurrentPage] = useState('calculator');
+ const [showOffsetOrder, setShowOffsetOrder] = useState(false);
+ const [offsetTons, setOffsetTons] = useState(0);
+ const [monetaryAmount, setMonetaryAmount] = useState(undefined);
+ const [calculatorType, setCalculatorType] = useState('trip');
+
+ useEffect(() => {
+ analytics.pageView(currentPage);
+ }, [currentPage]);
+
+ const handleOffsetClick = (tons, monetaryAmount) => {
+ setOffsetTons(tons);
+ setMonetaryAmount(monetaryAmount);
+ setShowOffsetOrder(true);
+ };
+
+ const renderContent = () => {
+ if (showOffsetOrder) {
+ return React.createElement(OffsetOrder, {
+ tons: offsetTons,
+ monetaryAmount: monetaryAmount,
+ onBack: () => setShowOffsetOrder(false),
+ calculatorType: calculatorType
+ });
+ }
+
+ return React.createElement(TripCalculator, {
+ vesselData: sampleVessel,
+ onOffsetClick: handleOffsetClick
+ });
+ };
+
+ return React.createElement('div', {
+ className: 'min-h-[600px] bg-gradient-to-b from-blue-50 to-green-50'
+ }, [
+ // Header
+ React.createElement('div', {
+ key: 'header',
+ className: 'bg-white shadow-sm py-4 px-6 mb-8'
+ }, [
+ React.createElement('div', {
+ className: 'flex items-center space-x-2'
+ }, [
+ // Bird icon would be here in a real implementation
+ React.createElement('h1', {
+ className: 'text-xl font-bold text-gray-900'
+ }, 'Puffin Offset')
+ ])
+ ]),
+
+ // Main content
+ React.createElement('div', {
+ key: 'main',
+ className: 'px-4 sm:px-6 flex justify-center'
+ }, renderContent()),
+
+ // Footer
+ React.createElement('div', {
+ key: 'footer',
+ className: 'bg-white mt-16 py-4 px-6 text-center text-gray-500'
+ }, 'Powered by Verified Carbon Offset Projects')
+ ]);
+ }
+
+ // Initialize React application
+ ReactDOM.createRoot(element).render(React.createElement(App, {}));
+ }
+ ";
+ }
+}
+
+/**
+ * Widget class for the calculator
+ */
+class Puffin_Calculator_Widget_Class extends WP_Widget {
+
+ /**
+ * Initialize the widget
+ */
+ public function __construct() {
+ parent::__construct(
+ 'puffin_calculator_widget',
+ 'Puffin Offset Calculator',
+ array('description' => 'Adds the Puffin Offset Calculator to a widget area')
+ );
+ }
+
+ /**
+ * Front-end display of the widget
+ */
+ public function widget($args, $instance) {
+ echo $args['before_widget'];
+
+ if (!empty($instance['title'])) {
+ echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
+ }
+
+ echo do_shortcode('[puffin_calculator]');
+
+ echo $args['after_widget'];
+ }
+
+ /**
+ * Back-end widget form
+ */
+ public function form($instance) {
+ $title = isset($instance['title']) ? $instance['title'] : 'Carbon Offset Calculator';
+ ?>
+
+
+
+
+