'use client'; import { useState } from 'react'; import { QRCalculatorData, QRGenerationResponse } from '@/src/types'; import { Download, Copy, Check, Loader2, QrCode } from 'lucide-react'; export default function QRTestPage() { // Form state const [calculationType, setCalculationType] = useState<'fuel' | 'distance' | 'custom'>('distance'); const [distance, setDistance] = useState('100'); const [speed, setSpeed] = useState('12'); const [fuelRate, setFuelRate] = useState('100'); const [fuelAmount, setFuelAmount] = useState('500'); const [fuelUnit, setFuelUnit] = useState<'liters' | 'gallons'>('liters'); const [customAmount, setCustomAmount] = useState('5'); const [vesselName, setVesselName] = useState(''); const [imo, setImo] = useState(''); // Response state const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [response, setResponse] = useState(null); const [copiedUrl, setCopiedUrl] = useState(false); const [copiedSvg, setCopiedSvg] = useState(false); // Example presets const presets = { distance: { calculationType: 'distance' as const, distance: 100, speed: 12, fuelRate: 100, }, fuel: { calculationType: 'fuel' as const, fuelAmount: 500, fuelUnit: 'liters' as const, }, custom: { calculationType: 'custom' as const, customAmount: 5, }, }; const loadPreset = (preset: keyof typeof presets) => { const data = presets[preset]; setCalculationType(data.calculationType); if ('distance' in data) { setDistance(data.distance.toString()); setSpeed(data.speed!.toString()); setFuelRate(data.fuelRate!.toString()); } if ('fuelAmount' in data) { setFuelAmount(data.fuelAmount.toString()); setFuelUnit(data.fuelUnit!); } if ('customAmount' in data) { setCustomAmount(data.customAmount.toString()); } }; const handleGenerate = async () => { setIsLoading(true); setError(null); setResponse(null); setCopiedUrl(false); setCopiedSvg(false); try { // Build request data based on calculator type const requestData: QRCalculatorData = { calculationType, timestamp: new Date().toISOString(), source: 'qr-test-page', vessel: vesselName || imo ? { name: vesselName || undefined, imo: imo || undefined, } : undefined, }; if (calculationType === 'distance') { requestData.distance = parseFloat(distance); requestData.speed = parseFloat(speed); requestData.fuelRate = parseFloat(fuelRate); } else if (calculationType === 'fuel') { requestData.fuelAmount = parseFloat(fuelAmount); requestData.fuelUnit = fuelUnit; } else if (calculationType === 'custom') { requestData.customAmount = parseFloat(customAmount); } // Call API const res = await fetch('/api/qr-code/generate', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestData), }); // Check HTTP status first if (!res.ok) { let errorMessage = `HTTP ${res.status}: ${res.statusText}`; try { const errorData = await res.json(); if (errorData.error) { errorMessage = errorData.error; } } catch { // Not JSON, use status text } throw new Error(errorMessage); } const result = await res.json(); if (!result.success) { throw new Error(result.error || 'Failed to generate QR code'); } setResponse(result.data); } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error occurred'); } finally { setIsLoading(false); } }; const copyToClipboard = async (text: string, type: 'url' | 'svg') => { try { await navigator.clipboard.writeText(text); if (type === 'url') { setCopiedUrl(true); setTimeout(() => setCopiedUrl(false), 2000); } else { setCopiedSvg(true); setTimeout(() => setCopiedSvg(false), 2000); } } catch (err) { console.error('Failed to copy:', err); } }; const downloadQR = (dataURL: string, format: 'png' | 'svg') => { const link = document.createElement('a'); link.href = format === 'png' ? dataURL : `data:image/svg+xml;base64,${btoa(response!.qrCodeSVG)}`; link.download = `qr-code-${calculationType}-${Date.now()}.${format}`; document.body.appendChild(link); link.click(); document.body.removeChild(link); }; return (
{/* Header */}

QR Code API Test Page

Test the QR code generation API for the carbon calculator

{/* Left Column - Input Form */}

Generator Configuration

{/* Example Presets */}
{/* Calculator Type */}
{/* Conditional Fields */} {calculationType === 'distance' && (
setDistance(e.target.value)} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
setSpeed(e.target.value)} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
setFuelRate(e.target.value)} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
)} {calculationType === 'fuel' && (
setFuelAmount(e.target.value)} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
)} {calculationType === 'custom' && (
setCustomAmount(e.target.value)} className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
)} {/* Vessel Information - Optional Metadata */}
Optional: Vessel Information (metadata only - not used in calculations)

Note: Vessel name and IMO are stored as metadata only. They are not used in carbon calculations.

setVesselName(e.target.value)} placeholder="e.g., My Yacht (optional)" className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm" />
setImo(e.target.value)} placeholder="e.g., 1234567 (optional)" className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm" />
{/* Generate Button */} {/* Error Display */} {error && (

Error: {error}

)}
{/* Right Column - Results */}

Generated QR Code

{!response && !isLoading && (

No QR code generated yet

Fill the form and click Generate

)} {isLoading && (

Generating QR code...

)} {response && (
{/* QR Code Display */}
Generated QR Code
{/* Download Buttons */}
{/* URL Display */}
{/* SVG Code */}