All checks were successful
Build and Push Docker Images / docker (push) Successful in 43s
ROOT CAUSE (Zen Debug Investigation): The API_BASE_URL constant was being evaluated when the module loaded, BEFORE window.env was populated by env-config.js. This caused the app to permanently use the fallback localhost:3001 instead of reading the production URL from the .env file. TIMING ISSUE: 1. Browser loads index.html 2. env-config.js loads (creates window.env) 3. main.tsx loads as ES module (DEFERRED) 4. Module imports checkoutClient → const API_BASE_URL executes 5. window.env NOT READY YET → falls back to localhost:3001 6. API_BASE_URL locked to wrong value forever THE FIX: Changed from module-level constants to request-time lazy evaluation. Now getApiBaseUrl() is called WHEN THE API REQUEST HAPPENS, not when the module loads. At that point window.env is guaranteed to exist. FILES CHANGED: - src/api/checkoutClient.ts: * Removed constant API_BASE_URL * All 3 functions now call getApiBaseUrl() at request time * Added logging to show which URL is being used - src/api/aisClient.ts: * Removed constant API_KEY * Added getApiKey() function with lazy evaluation * Same pattern for consistency and future-proofing This fixes: "FetchEvent for http://localhost:3001 resulted in network error" Now uses: https://puffinoffset.com/api (from .env file) 🔒 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
import axios from 'axios';
|
|
import type { VesselData } from '../types';
|
|
|
|
const API_BASE_URL = 'https://services.marinetraffic.com/api/vesselmasterdata/v3';
|
|
|
|
// Get API key at request time to ensure window.env is populated
|
|
const getApiKey = (): string | undefined => {
|
|
if (typeof window !== 'undefined' && window.env?.MARINE_TRAFFIC_API_KEY) {
|
|
return window.env.MARINE_TRAFFIC_API_KEY;
|
|
}
|
|
return import.meta.env.VITE_MARINE_TRAFFIC_API_KEY;
|
|
};
|
|
|
|
export async function getVesselData(imo: string): Promise<VesselData> {
|
|
const apiKey = getApiKey(); // Lazy evaluate at request time
|
|
|
|
// For development, return mock data if no API key is present
|
|
if (!apiKey) {
|
|
console.warn('No API key found - using mock data');
|
|
return getMockVesselData(imo);
|
|
}
|
|
|
|
try {
|
|
const response = await axios.get(API_BASE_URL, {
|
|
params: {
|
|
imo,
|
|
apikey: apiKey,
|
|
}
|
|
});
|
|
|
|
if (!response.data || response.data.errors) {
|
|
throw new Error('Vessel not found');
|
|
}
|
|
|
|
const data = response.data[0]; // API returns an array
|
|
|
|
return {
|
|
imo: imo,
|
|
vesselName: data.VESSEL_NAME || 'Unknown',
|
|
type: data.SHIP_TYPE || 'Unknown',
|
|
length: Number(data.LENGTH) || 0,
|
|
width: Number(data.BREADTH) || 0,
|
|
estimatedEnginePower: calculateEstimatedEnginePower(
|
|
Number(data.LENGTH),
|
|
Number(data.BREADTH),
|
|
data.SHIP_TYPE
|
|
)
|
|
};
|
|
} catch (error) {
|
|
console.error('AIS API Error:', error);
|
|
throw new Error('Failed to fetch vessel data. Please check your IMO number and try again.');
|
|
}
|
|
}
|
|
|
|
function calculateEstimatedEnginePower(length: number, width: number, type: string): number {
|
|
// Simplified power estimation based on vessel dimensions
|
|
const baselinePower = length * width * 5; // kW
|
|
|
|
// Apply vessel type multiplier
|
|
const typeMultiplier = {
|
|
'Yacht': 1.2,
|
|
'Passenger': 1.5,
|
|
'Cargo': 1.0,
|
|
'default': 1.0
|
|
}[type] || 1.0;
|
|
|
|
return Math.round(baselinePower * typeMultiplier);
|
|
}
|
|
|
|
// Mock data for development
|
|
function getMockVesselData(imo: string): VesselData {
|
|
return {
|
|
imo: imo,
|
|
vesselName: "Sample Yacht",
|
|
type: "Yacht",
|
|
length: 50,
|
|
width: 9,
|
|
estimatedEnginePower: 2250 // 50 * 9 * 5
|
|
};
|
|
} |