Matt 09eb2d3781
Some checks failed
Build and Push Docker Images / docker (push) Failing after 2m11s
Add comprehensive QR code system for carbon calculator
Implements complete QR code generation and decoding system for pre-filling calculator data:

- Add qrcode npm dependency (v1.5.4) and zod validation (v3.24.1)
- Create QR generation API endpoint at /api/qr-code/generate
- Implement Base64 URL-safe encoding/decoding utilities
- Add Zod validation schemas for all calculator types (fuel, distance, custom)
- Create QRCalculatorLoader wrapper component with loading/error states
- Add useQRDecoder custom hooks for automatic URL parameter processing
- Modify TripCalculator to accept initialData prop for pre-filling
- Integrate QRCalculatorLoader into main App routing
- Create test page at /qr-test for API testing and QR code visualization
- Support all three calculator types with proper validation
- Include vessel information (name, IMO) in QR data
- Add 30-day expiration for generated QR codes
- Provide PNG and SVG download options in test interface

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 18:28:51 +01:00

80 lines
2.1 KiB
TypeScript

/**
* QR Code Generation API Endpoint
* POST /api/qr-code/generate
*/
import { NextRequest, NextResponse } from 'next/server';
import { QRCalculatorData, QRGenerationResponse } from '@/src/types';
import { validateQRData, sanitizeQRData } from '@/src/utils/qrDataValidator';
import { generateCalculatorQRCode } from '@/src/utils/qrCodeGenerator';
export async function POST(request: NextRequest) {
try {
// Parse request body
const body = await request.json();
// Validate data
const validationResult = validateQRData(body);
if (!validationResult.valid) {
return NextResponse.json(
{
success: false,
error: validationResult.error || 'Invalid QR data',
},
{ status: 400 }
);
}
const data = validationResult.data as QRCalculatorData;
// Sanitize data to remove any unnecessary fields
const cleanedData = sanitizeQRData(data);
// Get base URL from request
const protocol = request.headers.get('x-forwarded-proto') || 'https';
const host = request.headers.get('host') || 'localhost:3000';
const baseUrl = `${protocol}://${host}`;
// Generate QR code
const { dataURL, svg, url } = await generateCalculatorQRCode(cleanedData, baseUrl);
// Set expiration time (30 days from now)
const expiresAt = new Date();
expiresAt.setDate(expiresAt.getDate() + 30);
// Prepare response
const response: QRGenerationResponse = {
qrCodeDataURL: dataURL,
qrCodeSVG: svg,
url: url,
expiresAt: expiresAt.toISOString(),
};
return NextResponse.json({
success: true,
data: response,
});
} catch (error) {
console.error('Error generating QR code:', error);
return NextResponse.json(
{
success: false,
error: error instanceof Error ? error.message : 'Failed to generate QR code',
},
{ status: 500 }
);
}
}
// Return method not allowed for other HTTP methods
export async function GET() {
return NextResponse.json(
{
success: false,
error: 'Method not allowed. Use POST to generate QR codes.',
},
{ status: 405 }
);
}