puffinOffsetCalculator/puffin-calculator-iframe/js/utils.js

187 lines
5.5 KiB
JavaScript

// 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,
})}`;
}
// Get currency by code
function getCurrencyByCode(code) {
return currencies[code] || currencies.USD;
}
// 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));
}
// Sample vessel data
const sampleVessel = {
imo: '1234567',
vesselName: 'Sample Yacht',
type: 'Yacht',
length: 50,
width: 9,
estimatedEnginePower: 2250
};
// Default portfolio for fallback
const DEFAULT_PORTFOLIO = {
id: 1,
name: "Puffin Maritime Portfolio",
description: "A curated selection of high-impact carbon removal projects focused on maritime sustainability.",
projects: [
{
id: "dac-1",
name: "Direct Air Capture",
description: "Permanent carbon removal through direct air capture technology",
shortDescription: "Direct air capture in Iceland",
imageUrl: "https://images.unsplash.com/photo-1553547274-0df401ae03c9",
pricePerTon: 200,
location: "Iceland",
type: "Direct Air Capture",
verificationStandard: "Verified Carbon Standard",
impactMetrics: {
co2Reduced: 1000
}
},
{
id: "ocean-1",
name: "Ocean Carbon Removal",
description: "Enhanced ocean carbon capture through marine permaculture",
shortDescription: "Marine carbon capture",
imageUrl: "https://images.unsplash.com/photo-1498623116890-37e912163d5d",
pricePerTon: 200,
location: "Global Oceans",
type: "Ocean-Based",
verificationStandard: "Gold Standard",
impactMetrics: {
co2Reduced: 5000
}
}
],
pricePerTon: 200,
currency: 'USD'
};
// Simplified analytics
const analytics = {
pageView: function(path) {
console.log(`Analytics pageView: ${path}`);
},
event: function(category, action, label) {
console.log(`Analytics event: ${category} - ${action} - ${label}`);
},
error: function(error, message) {
console.error(`Analytics error: ${message}`, error);
}
};
// Create portfolio API call (with fallback to default)
async function getPortfolios() {
try {
// In a real implementation, this would be an API call
// For demo purposes, we'll just return the default portfolio after a small delay
return new Promise((resolve) => {
setTimeout(() => resolve([DEFAULT_PORTFOLIO]), 1000);
});
} catch (error) {
console.warn('Failed to fetch portfolios from API, using fallback');
return [DEFAULT_PORTFOLIO];
}
}
// Create offset order API call (simulated)
async function createOffsetOrder(portfolioId, tons, dryRun = false) {
try {
// Simulate API call
return new Promise((resolve) => {
setTimeout(() => {
resolve({
id: `order-${Math.floor(Math.random() * 1000000)}`,
amountCharged: tons * 200 * 100, // in cents
currency: 'USD',
tons: tons,
portfolio: DEFAULT_PORTFOLIO,
status: 'completed',
createdAt: new Date().toISOString(),
dryRun: dryRun
});
}, 1500);
});
} catch (error) {
console.error('Failed to create offset order', error);
throw new Error('Failed to create offset order. Please try again.');
}
}
// Email validation
function validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
// Send form submission (simulated)
async function sendFormSubmission(data) {
return new Promise((resolve) => {
setTimeout(() => resolve({ success: true }), 1000);
});
}